Degree Blogg
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

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”.

4Jan/120

Complete Dump of Asp.net WebRequest

Posted by Njål

 


Alternate way of dumping logs

 

Here’s a simple but very handy method that lists out all relevant data for a Asp.net web request. Posted Parameters, Query String, Http Headers, Cookies and Session variables are returned – and can be logged out to file/console etc.

Note that this static method can be called anywhere from your code – it does not have to be inside a aspx/ashx etc. The only requirement is that the code must run inside IIS and a web request must be assosiated with the current thread.

 

 

 

public static string DumpRequest()
{
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("");
    sb.AppendLine("-------------  PostedParameters --------------");
    foreach (string key in HttpContext.Current.Request.Form.Keys.Cast<string>().OrderBy(f => f))
    {
        sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.Params[key]);
    }

    sb.AppendLine("");
    sb.AppendLine("-------------  Query String ------------------");
    foreach (string key in HttpContext.Current.Request.QueryString.Keys.Cast<string>().OrderBy(f => f))
    {
        sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.QueryString[key]);
    }

    sb.AppendLine("");
    sb.AppendLine("-------------  Http Headers -------------------");
    foreach (string key in HttpContext.Current.Request.Headers.Keys.Cast<string>().OrderBy(f => f))
    {
        sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.Headers[key]);
    }

    sb.AppendLine("");
    sb.AppendLine("--------------  Cookies -------------------------");
    foreach (string key in HttpContext.Current.Request.Cookies.Keys.Cast<string>().OrderBy(f => f))
    {
        sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Request.Cookies[key].Value + " - ExpireDate: " +  HttpContext.Current.Request.Cookies[key].Expires);
    }

    sb.AppendLine("");
    sb.AppendLine("---------------  Session ------------------------");
    foreach (string key in HttpContext.Current.Session.Keys.Cast<string>().OrderBy(f => f))
    {
        sb.AppendLine(key.PadLeft(40, ' ') + " : " + HttpContext.Current.Session[key]);
    }

    return sb.ToString();
}

 

The result looks like this::

-----------------------------------------  PostedParameters -----------------------------------------

-----------------------------------------  Query String ---------------------------------------------
                                username : ted@example.com

-----------------------------------------  Http Headers ---------------------------------------------
                                  Accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                          Accept-Charset : ISO-8859-1,utf-8;q=0.7,*;q=0.3
                         Accept-Encoding : gzip,deflate,sdch
                         Accept-Language : en-US,en;q=0.8
                           Cache-Control : max-age=0
                              Connection : keep-alive
                                  Cookie : timeOffset=-120; gs_u=1746198188:22843:26224:1320393450549; LANG=en; USER=a33f8…
                                    Host : dev.filemail.com
                              User-Agent : Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome..

-----------------------------------------  Cookies --------------------------------------------------
                                  __utma : 155161261.1943841533.1313506820.1324476330.1325070578.60 - ExpireDate: 01.01.0001 00:00:00
                                  __utma : 155161261.1943841533.1313506820.1324476330.1325070578.60 - ExpireDate: 01.01.0001 00:00:00
                                  __utmc : 260895642 - ExpireDate: 01.01.0001 00:00:00
                                  __utmz : 155161261.1313506820.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) - ExpireDate:
                                  __utmz : 155161261.1313506820.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none) - ExpireDate:
                       ASP.NET_SessionId : a2xlln05ibzzd2ajywhpizc0 - ExpireDate: 01.01.0001 00:00:00
                                    gs_u : 1746198188:22843:26224:1320393450549 - ExpireDate: 01.01.0001 00:00:00
                                    LANG : en - ExpireDate: 01.01.0001 00:00:00
                              timeOffset : -120 - ExpireDate: 01.01.0001 00:00:00
                                    USER : a33f8a58568f430e8a0d48115ac7b13c - ExpireDate: 01.01.0001 00:00:00

-----------------------------------------  Session --------------------------------------------------
                                       - : -
                              UserObject : 

 

12Jun/111

WebClient // HttpWebResponse – Problems with Chunked Transfer encoding

Posted by Njål

Doing a HTTP POST to a webserver using C# is pretty easy using the System.Net.HttpWebRequest. However - if you need to retrieve the answer/reply from the webserver - you'll often get an exception:

Exception: 'Unable to read data from the transport connection: The connection was closed.'

When looking at the HttpWebResponse in the debugger - the length of the response is -1, so something strange is going on here.

When investigating further in the VS 2010 debugger/ Fiddler, I found out that the webserver (IIS 7 in this case) is sending the response using Transfer-Encoding: Chunked - which is relatively common in HTTP 1.1. It means that the length of the message isn't specified in the HTTP Header Content-Length, but in the message itself.

Nothing wrong with this - but apparently HTTPWebResponse does not support Chunked Transfer Encoding (and thereby not HTTP 1.1).

The easiest way to fix this is to make sure the HttpWebRequest is sent using HTTP 1.0 - this way the server will reply with a HTTP Header specifying Content-Length.

HttpWebRequest wr = (HttpWebRequest)WebRequest.Create("http://www.degree.no");
wr.ProtocolVersion = Version.Parse("1.0");

An easier/alternative way of doing HTTP Communication in the .NET framework is the System.Net.WebClient class. But since it uses HttpWebRequest under its hood,  the same problem occurs here.

There is no way (afaik) to specify WebClient to use HTTP 1.0 - so use HttpWebRequest with HTTP 1.0 if you need to POST something to a server and read the response.

28Nov/101

ImageGen resize functionality for free!

Posted by Njål

ImageGen is a great little .NET library that basically resizes images on the fly. The typical use of it is on websides, blogs etc - where a image is resized just before sending it to the browser. It is often used in Umbraco CMS sites, but it can be used just as easily in any Asp.net site.

Here's an example:

http://server.degree.no/media/39263/untitled-19.png (original image)

http://server.degree.no/umbraco/ImageGen.aspx?image=/media/39263/untitled-19.png&width=150 (resized by ImageGen)

It is often very useful to resize a image to a height of e.g. 60 pixels while also ensuring that the width should not be greater than e.g. 200px.
ImageGen offers this in its PRO version:

This feature is the only true useful feature of the PRO version ($199 per domain!) I have ever had use for.  Here's a trick to achieve maxHeight / maxWidth functionality with the free version:

http://server.degree.no/umbraco/ImageGen.aspx?image=/media/39263/untitled-19.png&width=150&height=50&constrain=true

This resizes the image to a width of max 150px, height of max 50px, while preserving the aspect ratio.

Happy resizing!

13Nov/100

Configuring Log4net from code!

Posted by Njål

LOGGING!
Photo: A more traditional way of logging.

The first thing I do when creating a new .NET website/app is to add Log4net. I usually find some old code, and

  1. copy the log4net.dll,
  2. copy the log4net.config
  3. copy the c# code that loads the config file

For a lot of the smaller projects/solutions I am working on - there is no need at all to change log levels / appenders etc. during run time - so I configure log4net directly from my c# code. This means that I can drop the log4net.config file.

Here is a piece of code that creates a simple FileAppender. It can easily be modified to handle RollingFileAppenders etc..


Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.RemoveAllAppenders(); /*Remove any other appenders*/

FileAppender fileAppender = new FileAppender();
fileAppender.AppendToFile = true;
fileAppender.LockingModel = new FileAppender.MinimalLock();
fileAppender.File = Server.MapPath("/") + "log.txt";
PatternLayout pl = new PatternLayout();
pl.ConversionPattern = "%d [%2%t] %-5p [%-10c] %m%n%n";
pl.ActivateOptions();
fileAppender.Layout = pl;
fileAppender.ActivateOptions();

log4net.Config.BasicConfigurator.Configure(fileAppender);

//Test logger
ILog log =LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
log.Debug("Testing!");

The result of the log test is:
2010-11-13 14:52:46,611 [20] DEBUG [_Default ] Testing!
A good place to put this code is in the entrypoint of your App (the Main(string[] args) method), or in the Global.asax if you are creating a web app (remember to grant the NETWORK SERVICE user write access to the folder you are logging to).

Happy logging!

-N