Degree Blogg
25Jan/120

Sharepoint 2010 – access site usage statistics

Posted by Andreas

OK, so you made the assumption that Microsofts Sharepoint team would have provided a simple way to access something as common (and not to mention extremely useful!) as site usage statistics. Which pages and resources are accessed

  • at what time
  • for how long
  • how often
  • the browser type
  • http status
  • and last but definately not least: by who.

And not only did you assume this would be easily accessible, you also told a client you’d have it done in a couple of hours. I assume some of you that ended up here either got lucky straight away, or you have already spent way more time than expected and added yet another element to your list of reasons why Sharepoint will make you loose your hair prematurely.

If you assumed that this data should be available somewhere you were right. The trick is to know how to access it from your custom web part. The data is stored in the WSS_Logging database, in a table called RequestUsage. You can run a simple query just to see what’s in there and which fields you have access to:

SELECT *
FROM [RequestUsage] 

Then you can start getting a bit more creative. You see, the RequestUsage table contains statistics for all sorts of requests – like requests to the MetadataWebService. So depending on your needs, filter out the type of document types / extensions / paths you are interested in. I needed just to know the hit count of .aspx pages in a specific sub site, so my query looked somewhat like this:

SELECT distinct(DocumentPath), COUNT(*) as DocCount
    FROM [RequestUsage]
    WHERE DocumentPath LIKE '/Marketing%'
      AND ( DocumentPath LIKE '%.aspx'   )
GROUP BY DocumentPath      

This is not a lesson in SQL, but that query gives me a nice list of all .aspx documents accessed under the Marketing sub site with the corresponding hit count. To get the top 5 out of that result, you’ll end up with something like this:

with cte as (
    SELECT distinct(DocumentPath), COUNT(*) as DocCount
    FROM [RequestUsage]
    WHERE DocumentPath LIKE '/Marketing%'
      AND ( DocumentPath LIKE '%.aspx'   )
    GROUP BY DocumentPath )
select top 5 DocumentPath, DocCount from cte order by DocCount desc

 

So we have a query we would like to run, and then you can display the result in a web part. There are numerous ways to do that, and I won’t cover it here but I’ll show the C# code for running this query. The following code snippet is put together from my actual project, and should give you enough information to piece together a working method. Take note of how the connection string for the WSS_Logging database is retrieved:

// run with elevated privileges
SPSecurity.RunWithElevatedPrivileges(delegate()
{
    string connectionString = SPUsageApplication.DefaultApplication.UsageDatabase.DatabaseConnectionString;
    SqlConnection connection = new SqlConnection(connectionString);

    // build your query
    StringBuilder sb = new StringBuilder();
    sb.Append("with cte ");
    sb.Append("as ");
    sb.Append("( ");
    sb.Append("SELECT distinct(DocumentPath), COUNT(*) as DocCount ");
    sb.Append("FROM [RequestUsage] ");

    // ...
    // add all the WHERE filters you want here
    // ...

    sb.Append(" GROUP BY DocumentPath ");
    sb.Append("");
    sb.Append(") select top " + ItemCount + " DocumentPath, DocCount from cte order by DocCount desc");
    string sql = sb.ToString();

    SqlCommand command = new SqlCommand();
    command.Connection = connection;
    command.CommandText = string.Format(sql, SPContext.Current.Web.ServerRelativeUrl);
    command.CommandType = System.Data.CommandType.Text;
    command.Connection.Open();

    SqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
        // access the fields, for example document name
        string docName = reader["DocumentPath"].ToString().Substring(reader["DocumentPath"].ToString().LastIndexOf('/') + 1);
        docName = HttpUtility.UrlDecode(docName);

        // build an HTML table, add items to a list or whatever you prefer
        // ..
    }

    // close the db connection
    command.Connection.Close();

}

The magic lies in how you build and define the filter to suit your requirements.

19Jan/122

Custom mapping? No, I use Automapper!

Posted by thorhalvor

In the previous posts i wrote about web applications communicating with the backend through a JSON REST API. I mentioned that I like to design specific REST methods for the given Views. That means we have to do some mapping from the objects given by the backend to the viewmodel objects. Writing a custom mapping class is not rocket science but it is really boring to maintain when properties are removed or introduced during its lifetime.

Using Automapper from Jimmy Bogard can in some best-cases reduce the code needed to only two lines of code. No matter how many properties exist in the object.

Automapper has moved to github and you can read more about it there, and it is also available as an nuget pacakge.

I will not go in-depth, but let me give you some examples:

I have a Customer object with Firstname and Lastname. I also have an CustomerViewModel object with the same properties. To verify i have wrote the test below. Linenumber 5 and 6 are the only lines of code needed to perform the map.

Basic

 1: [Test]
 2: public void WhenMappingCustomerToViewModel_ThenAllPropertiesShouldBeMapped()
 3: {
 4:     var customer = new Customer{Firstname = "John",Lastname = "Johnsen"};;
 5:     Mapper.CreateMap<Customer, CustomerViewModel>();
 6: 
 7:     var customerViewModel = Mapper.Map<Customer>(customer);
 8: 
 9:     Assert.AreEqual(customer.Firstname,customerViewModel.Firstname);
 10:     Assert.AreEqual(customer.Lastname,customerViewModel.Lastname);
 11: }

AssertConfigurationIsValid

I will give you some more advanced examples later on in this posts, I will just start telling you about Automappers method “AssertConfigurationIsValid”. A very simple test that you always should add in your tests suite:

 1: [Test]
 2: public void WhenMappingCustomerToViewModel_ConfigurationShouldBeValid()
 3: {
 4:     Mapper.CreateMap<Customer, CustomerViewModel>();
 5:     Mapper.AssertConfigurationIsValid();
 6: }

AssertConfiguraitonIsValid will raise an exception if some of the properties in CustomerViewModel is NOT mapped from the Customer object. If for example only the CustomerViewModel has an Age property the given exception will be raised:

AutoMapper.AutoMapperConfigurationException : The following 1 properties on ns+CustomerViewModel are not mapped:
Age
Add a custom mapping expression, ignore, or rename the property on ns+Customer.

Lower- UpperCase does not matter

In Javscript and Json it is a standard to have lowercase properties. So if my CustomerViewModel had properties firstname and lastname and Customer has FirstName and LastName everything will just work. I do not have to change the mappingclass.

Flattening

If the Customer has an object of type Address, and Address has the property Line1, then this value will be automatically mapped if the CustomerViewModel has an property called AddressLine1. Eks Customer.Address.Line1 will be automatically mapped to CustomerViewModel.AddressLine1.

Projection

The Customer might have a property DateOfBirth of type DateTime, but in CustomerViewModel I have a property called Birthdate of type string. And I want this string to be in the format ddMMyyyy. In these cases i have to add a line when calling Mapper.CreateMap()

Mapper.CreateMap<Customer, CustomerViewModel>()
    .ForMember(d => d.BirthDate, o => o.MapFrom(s => s.DateOfBirth.ToString("ddMMyyyy")));

 

Mapping a IEnumerable<T> (added later because of specific request in email)

The framework support mapping of IEnumerable<T> as long as you have created a map for T.

 1: [Test]
 2: public void WhenMappingAListOfCustomersToViewModel_ThenAListWithAllTheViewModelsShouldBeMapped()
 3: {
 4:     var customer = new Customer{Firstname = "John",Lastname = "Johnsen"};
 5:     var customer2 = new Customer{Firstname = "hans",Lastname = "hansen"};
 6:     var customList = new List<Customer> { customer, customer2 };
 7: 
 8:     Mapper.CreateMap<Customer, CustomerViewModel>()
 9:         .ForMember(d => d.BirthDate, o => o.MapFrom(s => s.DateOfBirth.ToString("ddMMyyyy")));
 10: 
 11:     var customerViewModelList = Mapper.Map<IEnumerable<Customer>>(customList);
 12: 
 13:     Assert.AreEqual(customList.Count(), customerViewModelList.Count());
 14: }

 

So to summarize, Automapper is really powerful and can save you many hours of boring mapping implementation.

18Jan/121

CORS = XmlHttpRequest to other servers – without JSONP

Posted by Njål

 

imageAs Webstep guru Thor Halvor explained in the this excellent blogpost – there are security restrictions to prevent/limit cross domain access of XMLHttpRequest’s – the cornerstone of AJAX.

Flash and silverlight has the same restrictions – and solves this by using crossdomain.xml and clientaccesspolicy.xml. These files are placed on the server you want to communicate with – and must contain * or the domain you want to contact the server from.

Anyways – there is a similar mechanism that XMLHttpRequest supports. This mechanism is called CORS – Cross-origin resource sharing. It is a newer(2004) and preferred alternative to JSONP – and works more or less like the xml files mentioned above. The only difference is that it isn’t implemented as a file – it’s part of the HTTP Header. This makes it a bit more difficult to set up than the others.

When a javascript on siteA wants to make a request to siteB – then the script first makes an initial OPTIONS request to site B – and looks at the HTTP Header it receives.

Access-Control-Allow-Origin: *

 

If the value is * – then it means that XmlHttpRequests can communicate with that site – from any other server – and a regular XMLHttpRequest can be made just like you were communication with your own server. You can of course type in domain names here to prevent everybody from using your API.

Here’s how to configure this on an Microsoft IIS Server – Web.Config – under the <configuration> node

<system.webServer>
  <httpProtocol>
    <customHeaders>
       <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

 

So to sum it up: use CORS whenever possible, instead of hacking your way around with JSONP. You’ll have prettier code, better error handling and it’s safer to use with regard to XSS Attacks as far as I have understood. Also – CORS supports all types of HTTP requests (Get/Post/Put,Delete), while JSONP only supports Get.

Read more about CORS here:
http://my.opera.com/core/blog/2011/10/28/cors-goes-mainline

A third (and the newest) alternative is UMP – I might blog more about this some other time.

18Jan/120

JSONP in ASP.NET MVC 3

Posted by thorhalvor

When consuming a JSON REST API using AJAX the message is send as a XMLHttpRequest. Due to security reasons this is not allowed cross domain. Instead of returning the data as core JSON, JSONP is often used. The data will then not be parsed by the JSON parser but evaluated by the JavaScript interpreter.

Returning JSONP data does not come out of the box in ASP.NET MVC 3, but you can write a simple wrapper like this:

using System.Web.Mvc;
 
public class JsonpResult : JsonResult
{
    private const string CALLBACK_QUERYSTRING = "callback";
    private const string CALLBACK_CONTENTTYPE = "application/x-javascript";
 
    public override void ExecuteResult(ControllerContext controllerContext)
    {
        if (controllerContext != null)
        {
            var request = controllerContext.HttpContext.Request;
            object callback = request[CALLBACK_QUERYSTRING];
            if (callback == null)
            {
                controllerContext.RouteData.Values.TryGetValue(CALLBACK_QUERYSTRING, out callback);
            }
 
            var hasCallback = !string.IsNullOrWhiteSpace(callback ==null ? "" : callback as string);
 
            if (hasCallback)
            {
                SetContentTypeIfEmpty();
                var response = controllerContext.HttpContext.Response;
 
                response.Write(callback);
                response.Write("(");
                base.ExecuteResult(controllerContext);
                response.Write(")");
            }
            else
            {
                base.ExecuteResult(controllerContext);
            }
        }
    }
 
    private void SetContentTypeIfEmpty()
    {
        if (string.IsNullOrWhiteSpace(base.ContentType))
        {
            base.ContentType = CALLBACK_CONTENTTYPE;
        }
    }
}

 

It is now possible to just replace the jsonresult with jsonpresult in the code. If no callback is given it will work as normal.

        //return new JsonResult();
        return new JsonpResult();

 

When sending the request GET http://localhost/Website/Products/All?callback=myCallbackFunction the data will be wrapped like this: (same method used in last blogpost)

jsonp

18Jan/120

Asp.NET MVC 3 and JSON

Posted by thorhalvor

Creating a ASP.NET MVC 3 REST API returning JSON data is actually really simple.

If you have a MVC 3 Visual Studio project template and you add a Controller the default HomeController will be added:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

 

If you want this Index to return Json data the only thing needed is return JsonResult instead of a View.

        //return View();
        return new JsonResult();

 

To give an example I have created a ProductsController returning 3 products with the properties ProductId, Name and Price.

[AcceptVerbs(HttpVerbs.Get)]
public JsonResult All()
{
    var data = GetProducts();
    return new JsonpResult { Data = data, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}

Notice that you have to set JsonRequestBehavior.AllowGet. If forgotten you will get the self-explanatory errormessage:

This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.

 

When sending the request GET http://localhost/Website/Products/All, the method will return my three products:

(using Chrome with the extension JSONView)

json

As simple as that Smile

Tagged as: , , No Comments
17Jan/120

My favorite Web Application Architecture

Posted by thorhalvor

This is my first blogpost and I thought I should start writing about the web application architecture i normally choose these days, –if I am allowed by the client to refactor or start from scratch. Hopefully more blogposts will come out of this.

The first thing I do is splitting the Web Application in a html part and a JSON REST API part. Typically the Visual Studio folder structure looks like this:

  • WebApplication1.WebSite
  • WebApplication1.RestApi
HTML

I use the Razor viewengine in combination with Knockout.js to write the databinding and other than this the HTML is mostly consisting of a bunch of DIVs and script elements with jquery $.get or $.post’s. Normally I am that lucky in projects that I do not have to care about the “colors and stuff”, there is normally another guy taking care of the CSS. My main focus is therefore to get the databinding right and have a nice and clean architecture “downwards”.

REST API

I design the REST API service methods with the view in mind. So instead of having a super-generic method that works for “all web pages” I rather have several specific ones. I want to have as little logic in the client side as possible. I can then design my viewmodel-classes to consist of just the data needed, both translated and formated the way i want.

CQRS style: When working with the REST API I like to split the GET and POSTs as done in CQRS.

  • The GET-methods are fetching data from the database through a simple ORM like for example: EF, Dapper, Massive or Simple.Data. If working with a documentdatabase as for example RAVENDB the queries will go directly to its DocumentSession.
  • The POST-methods will have the business logic and sometimes be long running processes. A reliable service bus as nServiceBus is therefore to prefer. When working with long running and asynchronous processes special care must be taken when designing the UserInterface (HMTL pages). They can normally not be designed as done when working with request-response-based applications.
Environment:

If the team developers are writing tests and the application above is on GitHub using TeamCity with Continuous Deployment, then my day is perfect!

16Jan/120

jQuery validation not working in IE7 and IE8

Posted by Stian

jqueryWhen you create a new ASP.NET MVC 3 Project in Visual studio, your script folder will by default contain among others:

jquery-1.5.1.min.js
jquery.validate.min.js (which is version 1.8.0)

One of the first things you might want to do is update the jquery version to the latest version, which today is version 1.7.1

After doing this, your client side validation will stop working in Internet Explorer 7 and Internet Explorer 8.

This is because the jquery.validate version is not compatible with jquery versions > 1.6. The solutions is simple, you need to update your version of jquery.validate as well. You can find the current version 1.9 from Microsoft’s CDN or the latest version from GitHub here:

Microsoft Ajax CDN: http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js 
GitHub Jquery Validation: https://github.com/jzaefferer/jquery-validation/downloads

Remember that you can always find the latest javascript library in Microsofts CDN, see the complete list of available libraries here: http://www.asp.net/ajaxlibrary/cdn.ashx

13Jan/120

Conditional breakpoints in Visual Studio

Posted by Andreas

A Visual Studio feature worth checking out is the conditional breakpoint. In short, it allows you to set specific conditions that have to be met for a breakpoint to freeze execution. You have the choice between several types of conditions, like the value of a variable or the number of iterations over a specific breakpoint required before execution stops.

In the following example a list of car manufacturers is enumerated. I want the breakpoint to kick in when and only when the current car is “Subaru”. To achieve this, create a breakpoint like normal (F9) and right click the red marker in the left margin of the editor:

image

Select “Condition” which will open up the following dialog box:

image

Set your condition (standard boolean syntax, in my case car.Equals(“Subaru”) ) and when running the code the breakpoint will ignore all items where this condition if false.

This feature has several other varieties, and it saves you the manual job of iterating through 27 items before the one record that you want to follow through the next code block appears..

13Jan/122

TransactionScope – atomic transactions in C#

Posted by Andreas

From the world of databases we are familier with the term "atomic operation" : If not all operations succeed, don’t do any of them. An example is a banking system, where you move funds between accounts. If you deduct an amount from account #1 in operation 1, you definately want the amount to be added to account #2 in the next operation. If the second operation fails, roll back all previous changes.

Another example is if you are performing complex database operations that involve multiple queries run from a variety of classes and methods. You’ll eventually face the challenge of cleaning up any changes you might have made before an exception is thrown or an unexpected event occurs. This is where the System.Transactions.TransactionScope namespace comes in handy.

The System.Transactions assembly needs to be added to your project manually. Just add a reference like normal – you’ll find it under the .NET tab:

image

It requires your project to run on the .NET 4.0 platform, so change this in the project properties if necessary. Once referenced you can run your code in a transactional block, calling methods in different classes and commit it all (or roll back) in the end. My example below shows how two methods in different classes can do database operations within the same scope, and if an exception is thrown Complete() is not invoked and changes are rolled back:

static void RunInTransactionScope()
{
    using (TransactionScope trans = new TransactionScope(TransactionScopeOption.Required))
    {
        try
        {
            SomeClass1.DBOperation1();
            AnotherClass.DBOperation2();

            // commit
            trans.Complete();
        }
        catch (Exception e)
        {
            // all changes will be rolled back
        }

    } // transaction scope end
}

 

Take note of the different parameter options for the TransactionScope constructor. One in particular is the scope timeout, which is useful if your processing takes a long time or when you’re debugging.

Also check out a great tip for how to build dynamic WHERE clauses with LINQ in another post on this blog.

Tagged as: , 2 Comments
11Jan/120

ASP.NET MVC with Cleaner Data Annotations

Posted by Stian

 

While using data annotations with localization in your MVC model, you may end up with some untidy looking code like in this example, where all we do is adding display information and validation:

   1:  public class Character {
   2:    [Display(Name="Character_FirstName", ResourceType=typeof(ClassLib1.Resources))]
   3:    [Required(ErrorMessageResourceType=typeof(ClassLib1.Resources), 
   4:      ErrorMessageResourceName="Character_FirstName_Required")]
   5:    [StringLength(50, ErrorMessageResourceType = typeof(ClassLib1.Resources),
   6:      ErrorMessageResourceName = "Character_FirstName_StringLength")]
   7:    public string FirstName { get; set; }
   8:   
   9:    [Display(Name="Character_LastName", ResourceType=typeof(ClassLib1.Resources))]
  10:    [Required(ErrorMessageResourceType=typeof(ClassLib1.Resources), 
  11:      ErrorMessageResourceName="Character_LastName_Required")]
  12:    [StringLength(50, ErrorMessageResourceType = typeof(ClassLib1.Resources),
  13:      ErrorMessageResourceName = "Character_LastName_StringLength")]
  14:    public string LastName { get; set; }
  15:  }

 

While working on a project I found a NuGet Package which helped me to clean up this “mess”.

2012-01-11_0731

The extension is created by Phil Haack and derives from the DataAnnotationsModelMetadataProvider. The beauty of this extension is that you can set up a default resource type in Global.asax like this:

   1:  ModelMetadataProviders.Current = new ConventionalModelMetadataProvider(
   2:    requireConventionAttribute: false,
   3:    defaultResourceType: typeof(MyResources.Resource)
   4:  );

Note that the first argument, requireConventionAttribute, determines whether the conventions only apply to classes with the MetadataConventionsAttribute applied.

After you have configured the default resource type, it is no longer necessary to specify the ResourceType or ErrorMessageResourceType attributes. Also, the custom metadata provider looks up the resource key named the same as your property so that you are no longer required to specifying Display(Name=”FirstName”) as long as you match the property name and the resource name.

The same goes for validation attributes where you can use a resource key of {PropertyName}_{Attributename}, for example, to locate the error message for a RequiredAttribute, the provider finds the resource key FirstName_Required.

The “messy” data annotation code from above could with this extension look something like the code below, and still give the same result as long as you have the resources “FirstName” and “LastName” in your default ResourceType:

   1:  public class Character {
   2:    [Required]
   3:    [StringLength(50)]
   4:    public string FirstName {get; set;}
   5:   
   6:    [Required]
   7:    [StringLength(50)]
   8:    public string LastName {get; set;}
   9:  }

Hello good lookin’ !

You could of course provide some metadata, the metadata that you don’t supply is inferred based on the conventions. You may also like that if a value for a given resource is not found, the code falls back to using the property name as the label, but splits it using Pascal/Camel casing as a guide. Therefore in this case, the label is “First Name” and “Last Name”.