Pages

Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Friday, December 7, 2012

Introduction to DotNetAuth

Recently I have been working on implementation of OAuth protocol. The outcome was not that much bad, so I decided to make it available for others to use it free. Although I am still working on its features, it is fully functional. I have used it in several of my projects.

OAuth protocol is a protocol which is implemented by a lot of famous social networks and is the fundamental key to working with most of their APIs, specially to access to methods which requires some of identity of the requester. So if you want to integrate your website with Facebaook or Google Plus or LinkedIn etc probably your first step would be to handle OAuth protocol.

Also it is a common practice to use OAuth for authenticating user's in your website. Instead of the classic set of username/password credentials, you can simply deliver the user identification to these social networks and ask for user's primary set of information like name, date of birth, gender etc through their API.

OAuth protocol is a complete protocol as it considers all the parties(one which needs to authorize, one which need to make an authorized request, end user who authorizes) and all common scenarios in ways of communication between parties.

DotNetAuth is a an implementation of the OAuth protocol which only supports the consumption of protocol, and it is only for server side flow. So if you are the developing a website which wants to makes user-authorized requests to social network sites like Facebook or Google API this library is for. Also this library helps you take advantage of the OAuth protcol to identify users of your website and use OAuth for user membership(sign up, sign in features).

Source Code:
https://bitbucket.org/samnaseri/dotnetauth

Nuget Packages:

Install-Package DotNetAuth
Install-Package DotNetAuth.Profiles


Asp.Net MVC Sample:
This is just a sample to show what it would look like.
Just add above packages and then you can have the following methods in your ProfileController:

public class ProfileController : Controller
{
    ProfileProperty[] requiredProperties = new[] { ProfileProperty.Email, ProfileProperty.DisplayName, ProfileProperty.UniqueID, ProfileProperty.DisplayName };
    // GET: /Profile/
    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }
    public RedirectResult Login()
    {
        var userProcessUri = Url.Action("Callback""Profile"null, protocol: Request.Url.Scheme);
        var provider = LoginProvider.Get(LoginProviderRegistry.Facebook.Fullname);
        var authorizationUrl = DotNetAuth.Profiles.Login.GetAuthenticationUri(provider, new Uri(userProcessUri), new DefaultLoginStateManager(Session), requiredProperties);
        authorizationUrl.Wait();
        return Redirect(authorizationUrl.Result.AbsoluteUri);
    }
    // GET: /Process
    [HttpGet]
    public ActionResult Callback(string providerName)
    {
        var userProcessUri = Url.Action("Callback""Profile"null, protocol: Request.Url.Scheme);
        var provider = LoginProvider.Get(LoginProviderRegistry.Facebook.Fullname);
        var profile = DotNetAuth.Profiles.Login.GetProfile(provider, Request.Url, userProcessUri, new DefaultLoginStateManager(Session), requiredProperties);
        profile.Wait();
        return Content(profile.Result.ToString());
    }
}

And that's it.

Friday, November 30, 2012

Bundling using Cassette in Asp.Net MVC

I am a big fan of Cassette library. It is an ending to lots of problems you will face in managing your web application scripts and style sheets. Basically what it does is serving JavaScript files and CSS files in a much more efficient and manageable way.

In short these are benefits of using Cassette:
  • bundling assets
    • multiple files concatenation into single file, so fewer HTTP requests
    • reference management
    • avoiding including unnecessary assets in a page 
  • performance improvements
    • assets auto versioning and caching 
    • performance achievements through caching 
    • HTTP compression
  • good transforms
    • script minification
    • support for CoffeeScript
    • support for SASS 
    • support for LESS 
    • support for hogan html templates which means precompiled html templates 
    • embedding small images into CSS files 
  • a little bit of access control over script files. 
  • debug friendly
Although Cassette is for both JavaScript and style sheets, if you do it for JavaScript files the same process is for style sheets and HTML templates. So, let start by JavaScript files.

Setting up the Cassette in your web project

First of all we need to do a little work to make Cassette features working in our web projects.

The automatic way:

Using nuget package, just run the following command:
install-package cassette.aspnet

The manual way:

You may be a control freak like me, I need to do the things manually in order to make sure that I do know what is happening in my web application, and hence I know what is wrong in case of a failure.

So here are the things that should be done to make Cassette working:
  1. Configuring web.config to 
    1. add required HTTP module and HTTP handler 
    2. add Cassette.Views to razor page namespaces, you have to do this step for areas manually, even if using nuget package. 
  2. Adding CassetteConfiguration class 
  3. Add references to required assemblies:
    • Cassette
    • Cassette.Views
    • Cassette.Aspnet
    • AjaxMin
      For all the features:
    • Cassette.CoffeeScript
    • Cassette.Sass
    • Cassette.Hogan
    • IronRuby
    • IronRuby.Libraries
    • IronRuby.Libraries.Yaml
    • Jurassic
This is the HTTP module you need to add to configuration>system.web>httpModules:

<add name="CassetteHttpModule" type="Cassette.Aspnet.CassetteHttpModule, Cassette.Aspnet" />
You may add the same to configuration>system.webServer>httpModules.


This is the HTTP handler you need to add to configuration>system.web>httpHandlers

<add name="CassetteHttpHandler" path="cassette.axd" preCondition="integratedMode" verb="*" allowPathInfo="true" type="Cassette.Aspnet.CassetteHttpHandler, Cassette.Aspnet" />
You may add the same entry to  configuration>system.webServer>httpHandlers.

And you have to include Cassette.Views in configuration>system.web>pages>namespaces:

<add namespace="Cassette.Views" />
If you are using Asp.Net MVC Areas, Add the above namespace to every area's web.config.

How to implement Cassette

Simply there is only three steps:
1. create bundles to bundle a set of scripts together by writing the following line in CassetteConfiguration:

bundles.Add<ScriptBundle>("lib/js");
This will create a bundle named lib/js which bundles all files in lib/js folder.

2. reference bundles to specify which script is required in your razor page by writing:

Bundles.Reference("lib/js");
It records a flag that bundle lib/js should be rendered when rendering scripts.

3. create the script tag(s) to load all the referenced libraries. in your razor page you write:

@Bundles.RenderScripts();
It renders all the so far mentioned bundles into one or several script tags.

Step 1. Creating and configuration of bundles

In step one you specify which files to be included in a bundle called "lib/js", you may also specify more advanced setting for bundle, like how to search for files, which files should be ignored, etc.

When bundling you specify a folder path, then according to some rules, script files within that path will be added to the bundle. Default rules exclude -vsdoc.js files and also if alternative .min or .debug file exists, then only one file is picked.

Step 2. Adding references to scripts

In step two you only mention that the specified bundle is required, you can do this 'referencing bundles' anywhere, it could be the layout page, a partial view. So you ask for a bundle to be included only when it is required and at the place that requirement is raised. For example you have a partial view that requires a specific script, so you add a reference to that script in that partial view. Assuming that no other view or partial view has a demand for that script, then that script only will be loaded for pages which contains that partial view.

The reference you specify is a bundle path. So if you write @Bundles.Reference("X") then you should have bundles.Add("X") in your Cassette configuration, or you should have a bundles.Add("Y") where X can be find in Y.

Step 3. Rendering the actual script tags

In step three you actually create script tags. So the bundles you have mentioned so far using the @Bundles.Reference will be rendered into one or multiple script tags. If your compliation debug attribute is set to true, then Cassette does not join scripts and does not minify them, so you still can debug your scripts. In contrast, if debug="false", then Cassette concatenates scripts files into a single file and also minifies them.

It may be a little bit confusing, at least it was for me. As I described it here, the step one may seems unnecessary, but you should note that in step two "lib/js" does not refer to a scripts folder, but it is referring to the bundle we created at step one.

Rendering script tags is where you get the point of Cassette, the way that Cassette renders script tags and brings scripts into your page has several benefits. But before going forward to discuss the benefits, first let me describe some facts about how Cassette works, so then I can tell how those benefits are achieved.

  1. Cassette exposes a HTTP handler for sending back scripts to client.
  2. Cassette computes a hash for each bundle. If the scripts change, the hash value will change.
  3. Cassette will return a bundle even if you asked for a single script file. For example you asked for "lib/js/MySpecificLib.js", then Cassette will return bundle "lib/js".
  4. Cassette will include dependencies and order scripts based on their dependencies.

So the benefits are:

 - You can prevent direct access to your script libraries. So if you are using Cassette for all your resources  then you may restrict direct access to libraries folder.

 - Unless you created a bundle you can not reference to a script file. So there is a limited number of bundles all defined in CassetteConfiguration class. Each bundle is accessed via Cassette's HTTP handler and has a URL which is consisted of bundle's hash. So if you change the scripts then the hash changes and the URL changes, so the browser would not use the cached version and hence you forced browser to fetch the new version of bundle. And as long as the scripts are the same you can rely the browser caching. Here I have to point out an important guideline: put third parties libraries and your own libraries in different bundles, because they have different change frequencies  Your app's scripts change more often, so they bundle need to be reloaded more often.

 - When referencing you can be specific about exactly which scripts you need, you don't have to mention the bundle itself. If you specify a script file instead of a bundle, then cassette will render a script tag pointing to any bundle which contains that file, chances are that file already has been loaded once. However because you specified the file name rather than the bundle name, you can move that file to another bundle, for example make your bundles more granular and specific, without being worried about places which that bundle was referenced.

 - You only need to reference the scripts you directly need, you don't need to be worried about if you have included the required libraries which your scripts requires.

 - One important thing you should know is that the way script tags are rendered is dependent on compilation debug attribute. If it's value is true, Cassette will generate debug friendly script tags and script files are rendered as it is. In contrast, if debug value is false, then Cassette will generate efficient script tags and script files are concatenated and minified.

 - Probably you are using layout pages in a way that your pages are not concerned with the head section of html. Using Cassette you render scripts only in layout page and then reference the bundles in page whenever they are required, so when each page is served the scripts(bundles) related to that specific page is rendered.

Note: For simplicity, I have written this article for scripts. However the same story happens for style sheets, the only difference is that instead of ScriptBundle you use StylesheetBundle. And instead of @Bundles.RenderScripts() you will write @Bundles.RenderStylesheets() .

Targeted Bundles

When defining a bundle you can restrict it to a specific target. Actually, the Cassette itself referes to it as PageLocation, however you can use this feature beyond page location, so I named it targetted bundling.

Monday, November 21, 2011

MVC Tips #1, Passing HTML or Javascript as Data


Sometimes you need to render an html to output which the source of HTML is from your model. For security reasons rendering html directly from data requires to be explicitly requested, here is the 2 scenarios for doing so:

[AllowHtml]
If your model has a property which contains HTML content you add the AllowHtml property before the property. By doing so you inform the MVC that you expect html content in that property.
Although the it is named AllowHtml it also works for JavaScript.

@Html.Raw(Model.HtmlContent)
When rendering a Razor view to allow html content be rendered to output use @Html.Raw(Model.HtmlContent).

WARNING By using any of the above technique you need to make sure that the HTML or JavaScript content is safe. So if the data comes from some untrusted source you application will become vulnerable to attacks.

WARNING 2 Also pay attention to fact that AllowHtml also allows JavaScript, so dont assume that by applying this attribute only safe html code will be passed to client.


Note :
If you have a custom model binder and use pass the html values in your model, you may receive this exception:
A potentially dangerous Request.Form value was detected from the client
I found a solution for this problem at this Martijn Boland's blog post. which worked fine for me and you can learn about why this problem exists and how the solution works.

Tuesday, November 1, 2011

Asp.Net MVC : Setting Model as string and avoiding Illegal Characters in Path

If you for every reason need to set a page's model type to be string type, then you may face this exception:

Illegal Characters in path

Which seem to be weird, or you even may dont understand that the cause of the above problem is the Model type being string.
Actually the reason that you get the above exception is that in your Controller you as usual called the View method passing the model as the only argument and the model value is a string. But what you may have not pay attention to is that View method also has another override which accepts an string as the view name. So if you pass the model like this code:

return View("myStringModel");

In the above code you specified to go to page with the name "myStringModel" and such a page does not exists. Solution: My suggestion is to select the right overload by specifying the argument explicitly, like the below code:

return View(model: "myStringModel");