Tag Archives: MVc

Creating a KnockoutJS Model From an ASP.NET MVC Model

The Problem

In the previous article I showed how to load and populate an existing KnockoutJS view model which mirrored the properties of a C# model.  There is an obvious problem relating to maintainability here; when the C# model changes we need to manually update the KnockoutJS view model.  Fortunately there is a solution!

The Solution

To deal with this problem we can use the Knockout Mapping plugin which provides functionality to map JSON to KnockoutJS observables; you can either get it from the website or through NuGet.

If we simply want to map JSON to observables we can just use the mapping functionality of the plugin and use the return value directly as a view model.  The example below demonstrates this usage:

1 2 3 4 5 6 7 8 9 10 11 12
@using Quickstart.Web.Extensions
@model Quickstart.Web.Models.Person
@section scripts
{
<script type=“text/javascript”>
var viewModel = ko.mapping.fromJS(@Html.Raw(Model.ToJson()));
ko.applyBindings(viewModel);
</script>
}
<!– HTML for view knockout bindings etc –>

Note the use of the ToJson() extension method from the previous article

While this approach works to create a simple model, it is more likely that you will want to have a more complex view model which defines functions and calculated observables.  To accomplish this we simply need to create a typical KnockoutJS view model and use the mapping plugin within it:

1 2 3 4 5 6 7 8 9
var DynamicModelLoading = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.displayFullName = function(model) {
var fullName = model.firstName() + ” “ + model.lastName();
alert(fullName);
};
};

Here we give the “fromJS()” function three parameters:

  • The data: the JSON to be used to generate the observable variables
  • The mapping configuration: used to customise the mapping process (beyond the scope of this series but the documentation may be useful)
  • The update target: the object to create observables in

In the example above the data is the C# model serialized as JSON and the update target is the “self” variable which references the view model object itself.  This view model also defines a simple function which constructs and displays the Persons full name which can be bound to in the view.  This view model can then be created and applied to the view:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@using Quickstart.Web.Extensions
@model Quickstart.Web.Models.Person
@section scripts
{
<script type=“text/javascript” src=“/Scripts/ViewModels/DynamicModelLoading.js”></script>
<script type=“text/javascript”>
var viewModel = new DynamicModelLoading(@Html.Raw(Model.ToJson()));
ko.applyBindings(viewModel);
</script>
}
<!– HTML for view knockout bindings etc –>
<a href=“#” databind=“click:displayFullName”>Display full name</a>

Refrence:-

http://blog.json.codes/web-development/creating-a-knockoutjs-model-from-an-asp-net-mvc-model/

ASP.NET MVC: Using Ajax, Json and PartialViews

While working on a new ASP.NET MVC project, I had a simple objective: add a new record and refresh my View. After sifting through several sites I found several resources that lead me to accomplish my goal.

I’ve compiled my result into a new sample MVC Application that I created in Visual Studio that you can download here. I’ll explain what I did using that as my reference. It’s a trimmed down version of what I did on the actual project, but it will get the point across.

Let’s assume we want to have a View that lists some People from our data source. I started out by creating a Person data model:

public class Person
{
  public Guid Id { get; set; }
  public String FirstName { get; set; }
  public String LastName { get; set; }

  public Person()
  {
    Id = Guid.NewGuid();
  }
}

Next, I created some ViewModels so that I can work with strongly typed Views:

public class PersonIndexViewModel
  {
    public PersonListViewModel PersonListModel { get; set; }

    public AddPersonViewModel AddPersonModel { get; set; }
  }

  public class PersonListViewModel
  {
    public List PersonList { get; set; }
  }

  public class AddPersonViewModel
  {
    public String FirstName { get; set; }
    public String LastName { get; set; }
}

Next, I added a People folder in my Views folder and created a strongly typed Index View on my PersonIndexViewModel. I started out with building a table and doing a foreach to display each Person object. I moved that into a PartialView (.ascx) by creating a ParitialView in my Views/Shared folder (This blog post is very helpful for showing you how to use PartialViews). I called that PersonList.ascx and that is a strongly typed partial view on my PersonListViewModel.

Now, I can update my View to display that PartialView with this code:

<% Html.RenderPartial("PersonList", Model.PersonListModel); %>

Next, I want to be able to perform a delete action to remove a Person from the DB. You’ll notice I’m using an Ajax.ActionLink in my PersonList PartialView so that I can perform the delete with Ajax.

<%= Ajax.ActionLink("delete", "JsonDelete", "People",
new { Id = person.Id },
new AjaxOptions { Confirm = "Are you sure you want to Delete this Person? This action cannot be undone.",
HttpMethod = "Delete",
OnComplete = "JsonDelete_OnComplete" })%>

In the ActionLink, I specify the Action I want to call, pass the Person.Id and in the AjaxOptions I defined a JavaScript method that should be called on complete. In my People Controller I can now add the JsonDelete method:

[AcceptVerbs(HttpVerbs.Delete)]
public JsonResult JsonDelete(Guid Id)
{
  // call your Repository to delete the Person
  bool result = _personList.Remove(toDelete);

  // return a Json Object, you could define a new class
  return Json(new
  {
    Success = result,
    Message = result ? "The person has been deleted!" : "Error!"
  });
}

You would call your Repository to delete that Person and then return a new Json Object. What I did was define a couple of properties that I will reference from the JavaScript function to give feedback to the user. Here is the JavaScript function:

function JsonDelete_OnComplete(context) {

  var JsonDelete = context.get_response().get_object();

  if (JsonDelete.Success) {
    $(this).parents('tr.item').remove();
  }

  $("#message").html(JsonDelete.Message);
}

I found this link that showed me how to use “context.get_response().get_object();” to get the Json Object in JavaScript.

Now that I can delete, the next logical step would be the ability to add a new Person. I’ll start out by creating a new form that uses my AddPersonViewModel Model:

<% using (Ajax.BeginForm("JsonAdd", "People", new AjaxOptions { OnComplete = "JsonAdd_OnComplete" }))
 {%>
<fieldset>
  <legend>Add a Person</legend>
  <%= Html.LabelFor(model => model.AddPersonModel.FirstName)%>:
  <%= Html.TextBoxFor(model => model.AddPersonModel.FirstName, new { @class = "firstname" })%>
  <%= Html.ValidationMessageFor(model => model.AddPersonModel.FirstName)%>

  <%= Html.LabelFor(model => model.AddPersonModel.LastName)%>:
  <%= Html.TextBoxFor(model => model.AddPersonModel.LastName, new { @class = "lastname" })%>
  <%= Html.ValidationMessageFor(model => model.AddPersonModel.LastName)%>

  <input id="AddBtn" name="AddBtn" type="submit" value="Add" />
</fieldset>
<% } %>

Again, I use the Ajax.BeginForm to set the Action to call and define a JavaScript function to call on complete. To my Controller I add:

public JsonResult JsonAdd(AddPersonViewModel AddPersonModel)
{
  ...

  Person newPerson = new Person
  {
    FirstName = AddPersonModel.FirstName,
    LastName = AddPersonModel.LastName
  };

  // call your Repository to add the new Person
  _personList.Add(newPerson);

  // return a Json Object, you could define a new class
  return Json(new
  {
    Success = true,
    Message = "The person has been added!",
    PartialViewHtml = RenderPartialViewToString("PersonList", new PersonListViewModel {PersonList = _personList})
  });
}

One important thing here is the method “RenderPartialViewToString”. I ran across this which was a tremendous resource in solving my problem here, which was returning a Json Object with a rendered PartialView so that I could use JavaScript/jQuery to update the page.

The post I referenced above showed where you needed to create a base Controller to inherit from and that Controller defines the methods which will return a PartialView as an HTML string:

public abstract class BaseController : Controller
  {
    protected string RenderPartialViewToString()
    {
      return RenderPartialViewToString(null, null);
    }

    protected string RenderPartialViewToString(string viewName)
    {
      return RenderPartialViewToString(viewName, null);
    }

    protected string RenderPartialViewToString(object model)
    {
      return RenderPartialViewToString(null, model);
    }

    protected string RenderPartialViewToString(string viewName, object model)
    {
      if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

      ViewData.Model = model;

      using (StringWriter sw = new StringWriter())
      {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
      }
    }
}

Now with my JavaScript function is called, I can again reference my Json Object and then update the page:

function JsonAdd_OnComplete(context) {

  var JsonAdd = context.get_response().get_object();

  if (JsonAdd.Success) {
    $("#PersonList").html(JsonAdd.PartialViewHtml);
  }

  $("#message").html(JsonAdd.Message);
}

With this line:

$("#PersonList").html(JsonAdd.PartialViewHtml);

I have a div tag that surrounds my Html.RenderPartial call and I can use jQuery to just replace the HTML. Remember JsonAdd.PartialViewHtml contains the entire HTML of the newly rendered PartialView that we called from the Controller:

return Json(new
{
  Success = true,
  Message = "The person has been added!",
  PartialViewHtml = RenderPartialViewToString("PersonList", new PersonListViewModel {PersonList = _personList})
});

That just about sums it up how to use Ajax, jQuery, Json, and PartialViews in an effective manor in an ASP.NET MVC application.

Refrence:-

http://www.atlanticbt.com/blog/asp-net-mvc-using-ajax-json-and-partialviews/

Building forms for deep View Model graphs in ASP.NET MVC

ASP.NET MVC 2 introduced a multitude of strongly-typed helpers for building form elements for strongly-typed views. These strongly-typed helpers use lambda expressions to build a complete input element, including the correct name and value for the element.

The lambda expressions are quite powerful, allowing you to build quite complex edit models and have model binding put everything back together again. A complex view model type such as:

public class ProductEditModel
{
    public string Name { get; set; }
    public PriceEditModel Price { get; set; }

    public class PriceEditModel
    {
        public decimal Value { get; set; }
        public string Currency { get; set; }
    }
}

Can be quite easily built in a view:

@using (Html.BeginForm()) {
    <p>
        @Html.LabelFor(m => m.Name)
        @Html.TextBoxFor(m => m.Name)
    </p>
    <p>
        @Html.LabelFor(m => m.Price.Currency)
        @Html.TextBoxFor(m => m.Price.Currency)
    </p>
    <p>
        @Html.LabelFor(m => m.Price.Value)
        @Html.TextBoxFor(m => m.Price.Value)
    </p>
}

As long as we’re using the full model expression from the top-most model type to build the input elements, the correct HTML will be built. Suppose that you want to now pull that PriceEditModel out into a partial, and keep its view separate from the parent view. We change our view to instead render a partial for the Price property:

@using (Html.BeginForm()) {
    <p>
        @Html.LabelFor(m => m.Name)
        @Html.TextBoxFor(m => m.Name)
    </p>
    @Html.Partial("_PriceEditModel", Model.Price);
}

And our partial is just the extracted view code, except now built against the PriceEditModel type:

@model ProductEditModel.PriceEditModel

<p>
    @Html.LabelFor(m => m.Currency)
    @Html.TextBoxFor(m => m.Currency)
</p>
<p>
    @Html.LabelFor(m => m.Value)
    @Html.TextBoxFor(m => m.Value)
</p>

However, the resultant HTML no longer matches up the model members correctly. Although the screen looks right:

image

When we look at the actual HTML, something’s not right any more:

image

Instead of our member name having the correct parent member in its name as “Price.Currency”, we only see “Currency”. Sure enough, when we get to our POST action, the Price member is null as model binding could not line things up any more:

image

Not exactly what we want to do here!

So what are our options? In order to make sure model binding works for models with partials, we can scope our models in our partials to the parent type. That is, make our partial’s model type “ProductEditModel” instead of “PriceEditModel”.

Not a very appealing option!

We do have a better option, with the MVC 2 feature of templated helpers. Templated helpers elegantly solve the deep View Model graph problem.

Building with templated helpers

Templated helpers are different than partials in that special contextual information from the parent is passed down to the child as long as we’re using the Html.EditorXyz() HtmlHelper methods. To convert our view to use templated helpers, let’s just build an editor template for each view model type we have:

image

These are just normal partials in Razor, with the exception that they’re placed in the special EditorTemplates folder. In our ProductEditModel partial, we just move what we had in our Edit view over:

@model ProductEditModel

<p>
    @Html.LabelFor(m => m.Name)
    @Html.TextBoxFor(m => m.Name)
</p>
@Html.EditorFor(m => m.Price)

There is one slight difference here, however. Instead of rendering a partial for Price, we render the editor for the Price member. The PriceEditModel template is just what we had in our original partial with no changes needed:

@model ProductEditModel.PriceEditModel

<p>
    @Html.LabelFor(m => m.Currency)
    @Html.TextBoxFor(m => m.Currency)
</p>
<p>
    @Html.LabelFor(m => m.Value)
    @Html.TextBoxFor(m => m.Value)
</p>

The difference now is that our templated helper knows that the parent model used the “Price” member to build out this partial. In our parent Edit view, things become a bit simpler:

@using (Html.BeginForm()) {
    
    @Html.EditorForModel()

    <input type="submit" />
    
}

ASP.NET MVC will look at the type of the model to see if an editor template exists for that specific model type when we call the EditorForModel method. Because we built editor templates for each specific model type, it doesn’t matter where in the hierarchy these nested types exist. ASP.NET MVC will keep passing in the parent’s context so that deep nested graphs contain the right context information.

Looking at the resultant HTML, we can confirm that everything looks good there:

image

The input element’s name now has the correct parent property name in its value. Debugging into the POST action confirms that the model binding now works correctly:

image

With the templates helpers of ASP.NET MVC 2, we can now build nested models in our views and still take advantage of features like partials. The only caveat is that we need to make sure we build our views using templates helpers and the Html.EditorXyz methods. Otherwise, our views are minimally impacted.

And just to get a side complaint in, this was very annoying to build in MVC 1.0, to build nested hierarchies with strongly typed helpers respecting graphs including collection types all the way down. Just more code I got to delete with the later versions of MVC!

Refrence:-

http://lostechies.com/jimmybogard/2011/09/07/building-forms-for-deep-view-model-graphs-in-asp-net-mvc/

Binding to Models with Array Properties in ASP.NET MVC

One of the common tasks I encounter periodically is submitting a simple array of strings or numbers from JavaScript to a controller method for processing.  It seems like I struggle often trying to make it work.  So, this time I decided to develop a simple and easy to use solution.  I decided to utilize custom model binder capabilities available in ASP.NET MVC.  To use this method you have to define a model and a binder that will populate the model.  In my case my binder assume that the data is submitted as a post or a get, pulling the data from either form collection or query string collection from the request object.  It also assumes that my array is the only data submitted.  In my case my model has single property – List of strings.  Let’s take a look at the code.

using System.Collections.Generic;
using System.Web.Mvc;

namespace MyApp
{
    [ModelBinder(typeof(ListOfStringsModelBinder))]
    public class ListOfStringsModel
    {
        public List<string> Numbers { get; set; }
    }
}

The code above really does not need commenting.  The only interesting part is that I specify the binder I will use for the model.

using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace MyApp
{
    public class ListOfStringsModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext.HttpContext.Request.Form.Count > 0)
            {
                var serializer = new JavaScriptSerializer();
                return serializer.Deserialize<ListOfStringsModel>(controllerContext.HttpContext.Request.Form[0]);
            }
            if (controllerContext.HttpContext.Request.QueryString.Count > 0)
            {
                var serializer = new JavaScriptSerializer();
                return serializer.Deserialize<ListOfStringsModel>(controllerContext.HttpContext.Request.QueryString[0]);
            }
            return null;
        }
    }
}

The code above check both form and query string trying to pull submitted data out of either.  Then I use JavaScriptSerializer to push the data into the model.  I could have used Json.NET just as well, but for demo purposes this is just as good.  This is it.  To consume this code just add ListOfStringsModel as your parameter to a controller method.

[HttpPost]
 public ActionResult ProcessArrayData(ListOfStringsModel model)
 {
      return null;
 }

Then you can use jQuery to submit the payload

function sendArray() {
    var payload = [];
    // push data into array
    $.ajax({
        url:  'ProcessArrayData',
        data: JSON.stringify({ numbers: payload }),
        type: 'post',
        datatype: 'json',
        traditional: true,
        success: function (data) {
        },
        error: function (jqXHR, textStatus, errorThrown ) {
            alert('Error');
        }
    });
}

And there you go – simple and repeatable way to send array data to the server.

Enjoy.

Thanks.

Refrence;-

http://dotnetspeak.com/2013/06/binding-to-models-with-array-properties-in-asp-net-mvc

ASP.NET MVC 4 Beta

A few days ago we released the ASP.NET MVC 4 Beta.  This is a significant release that brings with it a bunch of great new features and capabilities.

The ASP.NET MVC 4 Beta release works with VS 2010 and .NET 4.0, and is side-by-side compatible with prior releases of ASP.NET MVC (meaning you can safely install it and not worry about it impacting your existing apps built with earlier releases).  It supports a “go-live” license that allows you to build and deploy production apps with it.  Click here to download and install it today.

The ASP.NET MVC 4 Beta will also be built-into the upcoming VS11 / .NET 4.5 beta that is coming out shortly.  This week’s beta doesn’t work with the previous VS11 developer preview that shipped last September – if you are using the VS11 Developer Preview (or have it installed) you’ll want to wait until the VS 11 beta is released before trying out the new ASP.NET MVC 4 Beta functionality.

ASP.NET MVC 4 Features

The ASP.NET MVC 4 Beta includes a bunch of great new features and capabilities.  Some of the highlights include:

  • Bundling and Minification – ASP.NET MVC 4 includes the new bundling and minification support we are also adding to ASP.NET 4.5.  These features enable you to build web applications that load faster and feel more responsive to users, by minimizing the number and size of HTTP requests that your pages make.  Included with the MVC 4 beta are new “cache busting” helper methods that enable easy proxy caching of bundled files (with automatic invalidation if you change the cached CSS or JavaScript).  You can learn more about bundling and minification from my previous blog post about it.
  • Database Migrations – ASP.NET MVC 4 includes the new Entity Framework 4.3 release, which includes a bunch of great new features.  One of the most eagerly anticipated features it provides is database migration support.  This enables you to easily evolve your database schema using a code focused migration approach – and do so while preserving the data within your database.  I’ll blog more about this in the future – you can also see a walkthrough of database migrations in this tutorial.
  • Web API – ASP.NET MVC 4 includes some fantastic new support for creating “Web APIs”.  This enables you to easily create HTTP services and APIs that can be programmatically called from a broad range of clients (ranging from browsers using JavaScript, to native apps on any mobile/client platform).  The new Web API support also provides an ideal platform for building RESTful services.  I’ll be blogging much more about this support soon – it is really cool, and opens up a bunch of new opportunities.  There are several tutorials, samples and screencasts covering ASP.NET Web API on the ASP.NET site to help you get started.
  • Mobile Web – ASP.NET MVC 4 includes new support for building mobile web applications and mobile web sites, and makes it much easier to build experiences that are optimized for phone and tablet experiences. It includes jQuery Mobile, and includes new support for customizing which view templates are used depending upon what type of device is accessing the app.  See the ASP.NET MVC 4 tutorial series.
  • Razor Enhancements – ASP.NET MVC 4 includes V2 of our Razor View engine.  Razor V2 includes a bunch of juicy enhancements that enable you to make your view templates even cleaner and more concise – including better support for resolving URL references and selectively rendering HTML attributes.
  • Async Support and WebSockets – You’ll be able to take advantage of some additional language and runtime capabilities when using ASP.NET MVC 4 with .NET 4.5 and VS 11.  Async support is one of the big ones, and the ASP.NET MVC runtime support for this combined with the new C#/VB async language enhancements (which are super elegant and clean) is going to enable you to write incredibly scalable applications.  You will also be able to take advantage of the new WebSocket support built-into .NET 4.5 to build applications with even richer browser/server communication.

I’ll be blogging a lot more about the above features in the weeks and months ahead.  This is going to be an exciting release. There is a lot there that will both make you more productive (Bundling/Minification, Database Migrations, Razor V2) as well as enable you to build even richer web applications and experiences (Web API, Mobile Web, WebSockets).

Learning More About ASP.NET MVC 4

I gave a tech-talk about the new ASP.NET MVC 4 Beta at the Belgium and Dutch TechReady events last week.  It provides a good overview that you can use to quickly come up to speed on the release.

You can watch or download a video of the talk for free via Channel9:

image

You can also download my slides (feel free to re-use them however you want).

Summary

I’m really excited about the upcoming ASP.NET releases we have coming out this year.  ASP.NET 4.5 and ASP.NET MVC 4 are going to deliver a ton of new capabilities and enhancements, and the tooling updates we have coming with VS 11 and WebMatrix make the developer experience awesome.

I’ll be blogging a lot more about them in the weeks and months ahead.

Refrence by:-

https://weblogs.asp.net/scottgu/asp-net-mvc-4-beta

ASP.NET MVC Model binding to a list.

I’m writing this post since I had a lot of problems finding out how Model binding works in ASP.NET MVC.

This behavior has changed in the beta and the final. This causes that some blog posts on the internet are inaccurate.

But let’s set things straight.

Create a MVC Project, leave everything default and add Product in your Models folders with the following (very simple) code:

namespace BlogPost.Models
{
    public class Product
    {
        public string Name { get; set; }
    }
}

Then add a ProductsController (in the Controllers folder) with the following code:

using System.Collections.Generic;
using System.Web.Mvc;
using BlogPost.Models;

namespace BlogPost.Controllers
{
    public class ProductsController : Controller
    {
        public ActionResult Add()
        {
            return this.View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Add(IList<Product> products)
        {
            return this.View();
        }
    }
}

With the following markup:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Add up to 10 products to the database
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        Add up to 10 products to the database</h2>
    <%
        using (Html.BeginForm())
        {
            for(int x = 0;x <= 9;x++)
            {
                %>
                <fieldset>
                    <legend>Product <%=x %>:</legend>
                    <input type="text" name="products[<%=x %>].Name" />
                </fieldset>
                <%
            }

            %><input type="submit" name="submitForm" value="Save products" /><%
        }
    %>
</asp:Content>

Now put a breakpoint in the Add function in your ProductsController that handles the Http Post

 

Enter 10 names, and hit the submit button at the bottom.

Visual Studio will break on your this.View(). Hover over your products parameter and you’ll see something in the lines of this:

Not too hard is it?

A little bit more in depth:

ASP.NET MVC binds your HTML input to your parameter through the default model binder. I recommend you read the source code available on http://aspnet.codeplex.com/SourceControl/changeset/view/23011

If you want to step through the source code using your application I refer you to Steve Sanderson’s excellent blog post.

If you take a look at the generated HTML source code you’ll notice this:

<fieldset>
    <legend>Product number 0:</legend>
    <input type="text" name="products[0].Name" />
</fieldset>
<fieldset>
    <legend>Product number 1:</legend>
    <input type="text" name="products[1].Name" />
</fieldset>

The name ‘products’ is VERY important, since this specifies that it your input should be bound to the ‘products’ parameter in your controller action.

Then the index between brackets:

IT MUST START FROM 0 AND BE CONTINUES!

Then the .Name, which specifies that your input should be placed in the Name property (not just a public variable, but a property with a get/set) (see code above).

You can repeat this for multiple properties, and group them by product.

That’s it for simple model binding.

Hope it helps.

Refrence-:

http://kristofmattei.be/2009/10/19/asp-net-mvc-model-binding-to-a-list/

Implementing User Confirmation and Password Reset with One ASP.NET Identity – Pain or Pleasure

Recently, I was trying to introduce GitHub and Twitter login for my TextUml, it was using the simple membership which has out of the box support for Twitter login, my attempt to create a client for GitHub OAuth2 failed, it seems the OAuthWebSecurity was receiving different query string name for provider from GitHub, anyway I did not want to invest too much time as Microsoft is coming up with a new Membership system called ASP.NET Identity (also the default in ASP.NET MVC 5) and I want to give it a try as the server side of TextUml is already running on all the edge versions of different packages.

Once installed, I quickly realized that it is not at all compatible with earlier versions of Membership, you have to create your own solution to migrate your existing data but the initial thing that surprised me that there is no built-in support for user confirmation and password reset. The user confirmation is when a user signs up, your application sends an email with a link, when the user visits the link the account is confirmed. And reset password is when user forgets password, s/he provides the email and the application sends an email (if matched) with a link, when the link is visited, it allows the user to set new password. Pretty standard stuff and these are available in the current simple membership and it worked pretty nicely in my projects. To implement these features it is obvious that I have to store few additional data like confirmation token, a flag whether it is confirmed, reset password token and its expiration timestamp. Though the above MSDN blog post has a bullet list of features but I find that the customization is more towards the additional attributes of user rather than injecting your own logic in the login process, you will find it shortly. So to store this data, I have created a new class called Token:

Token

              [Table("Tokens"), CLSCompliant(false)]
              public class Token
              {
                  private static readonly TimeSpan ResetPasswordExpireTimeframe =
                      TimeSpan.FromDays(1);
              
                  [Obsolete("Used by the underlying ORM.")]
                  public Token()
                  {
                  }
              
                  public Token(string userId, bool requiresActivation)
                  {
                      UserId = userId;
              
                      if (requiresActivation)
                      {
                          ActivationToken = GenerateToken();
                      }
                      else
                      {
                          MarkActivated();
                      }
                  }
              
                  [Key]
                  public string UserId { get; set; }
              
                  [ForeignKey("UserId")]
                  public virtual User User { get; set; }
              
                  public DateTime? ActivatedAt { get; set; }
              
                  [StringLength(128)]
                  public string ActivationToken { get; set; }
              
                  [StringLength(128)]
                  public string ResetPasswordToken { get; set; }
              
                  public DateTime? ResetPasswordTokenExpiredAt { get; set; }
              
                  public bool HasResetPasswordTokenExpired
                  {
                      get
                      {
                          return ResetPasswordTokenExpiredAt > Clock.UtcNow();
                      }
                  }
              
                  public bool CanActivate(string token)
                  {
                      return ActivatedAt == null &&
                          string.Equals(
                              ActivationToken,
                              token,
                              StringComparison.OrdinalIgnoreCase);
                  }
              
                  public void MarkActivated()
                  {
                      if (ActivatedAt != null)
                      {
                          return;
                      }
              
                      ActivatedAt = Clock.UtcNow();
                  }
              
                  public void GenerateResetPasswordToken()
                  {
                      ResetPasswordToken = GenerateToken();
                      ResetPasswordTokenExpiredAt = Clock.UtcNow()
                          .Add(ResetPasswordExpireTimeframe);
                  }
              
                  public void ExpireResetPasswordToken()
                  {
                      ResetPasswordTokenExpiredAt = Clock.UtcNow();
                  }
              
                  private static string GenerateToken()
                  {
                      var buffer = new byte[16];
              
                      using (var crypto = new RNGCryptoServiceProvider())
                      {
                          crypto.GetBytes(buffer);
                      }
              
                      return HttpServerUtility.UrlTokenEncode(buffer);
                  }
              }
              

The Token has one-to-one relation with the User, I am using ActivatedAt as a confirmation flag, but it can be a boolean property as well, there are few other helper methods which we would see in action shortly. Now, whenever a user is going to be created I have to create the corresponding token as well. For creating a new user it has CreateLocalUser method of the IdentityStoreManager class. We can use it for creating the user then we can persist the corresponding token, but in that case we are not treating it as single unit of work (multiple SaveChanges of DbContext). So it is better if I create an overloaded version, but in that case I have to create an inherited class of IdentityStoreManager.

IdentityStoreManager

              [CLSCompliant(false)]
              public class AppIdentityStoreManager : IdentityStoreManager
              {
                  private readonly AppIdentityStoreContext context;
              
                  public AppIdentityStoreManager(AppIdentityStoreContext storeContext) :
                      base(storeContext)
                  {
                      context = storeContext;
                  }
              
                  public async Task<string> CreateLocalUser(
                      IUser user,
                      string password,
                      bool requiresActivation)
                  {
                      ValidateUser(user);
                      ValidatePassword(password);
              
                      if (!(await context.Users.Create(user)))
                      {
                          return null;
                      }
              
                      if (!(await context.Secrets.Create(
                          new UserSecret(user.UserName, password))))
                      {
                          return null;
                      }
              
                      if (!(await context.Logins.Add(
                          new UserLogin(user.Id, LocalLoginProvider, user.UserName))))
                      {
                          return null;
                      }
              
                      var token = new Token(user.Id, requiresActivation);
              
                      var dataContext = (DataContext)context.DbContext;
                      dataContext.Tokens.Add(token);
              
                      await dataContext.SaveChangesAsync();
              
                      return token.ActivationToken;
                  }
              
                  private void ValidatePassword(string password)
                  {
                      if (string.IsNullOrWhiteSpace(password))
                      {
                          throw new ArgumentException("Password is required.", "password");
                      }
              
                      string error;
              
                      if (!PasswordValidator.Validate(password, out error))
                      {
                          throw new IdentityException(error);
                      }
                  }
              
                  private void ValidateUser(IUser user)
                  {
                      if (user == null)
                      {
                          throw new ArgumentNullException("user");
                      }
              
                      if (string.IsNullOrWhiteSpace(user.UserName))
                      {
                          throw new ArgumentException("user.UserName");
                      }
              
                      string error;
              
                      if (!UserNameValidator.Validate(user.UserName, out error))
                      {
                          throw new IdentityException(error);
                      }
                  }
              }
              

If you compare the above code with the original CreateLocalUser method, you would see I had to duplicate almost all of the code instead of reusing the existing building blocks.

Now, that we have created the user, lets move to the login part, as you can guess we also have to consider the confirmation flag along with the user name and password, unless the user is confirmed s/he is not allowed to login even the credential matches. The user name and password matching happens in the Validate method of UserSecretStore class and the confirmation checking should go there. The Validate method is not virtual, but the good news is the UserSecretStore class implements IUserSecretStore interface, which means we can create a new class with our custom logic that implements the interface and plugs it in.

UserSecretStore

              [CLSCompliant(false)]
              public class AppUserSecretStore : IUserSecretStore
              {
                  private readonly DataContext dataContext;
                  private readonly UserSecretStore<UserSecret> store;
              
                  public AppUserSecretStore(DataContext db)
                  {
                      dataContext = db;
                      store = new UserSecretStore<UserSecret>(db);
                  }
              
                  public Task<bool> Delete(string userName)
                  {
                      return store.Delete(userName);
                  }
              
                  public Task<bool> Create(IUserSecret userSecret)
                  {
                      return store.Create(userSecret);
                  }
              
                  public Task<bool> Update(string userName, string newSecret)
                  {
                      return store.Update(userName, newSecret);
                  }
              
                  public async Task<bool> Validate(string userName, string loginSecret)
                  {
                      var activated = await dataContext.Tokens
                          .AnyAsync(t =>
                              t.ActivatedAt != null &&
                              t.User.UserName == userName);
              
                      return activated &&
                          await store.Validate(userName, loginSecret);
                  }
              
                  public Task<IUserSecret> Find(string userName)
                  {
                      return store.Find(userName);
                  }
              }
              

In the above, we created an instance of the same UserSecretStore class internally and delegated all our method calls to it, the only exception is the Validate method where we are checking confirmation status before delegating. Now, to plug it in we have to create another inherited class from IdentityStoreContext:

IdentityStoreContext

              [CLSCompliant(false)]
              public class AppIdentityStoreContext : IdentityStoreContext
              {
                  public AppIdentityStoreContext(DataContext dataContext) :
                      base(dataContext)
                  {
                      Secrets = new AppUserSecretStore(dataContext);
                  }
              }
              

Next, In order to keep my rest of the application code mixing with this new membership code I created a MembershipService that as a façade. With the above sign-up and sign-in it looks like the following:

MembershipService

              public class MembershipService : IMembershipService
              {
                  private readonly DataContext dataContext;
              
                  public MembershipService(
                      DataContext dataContext,
                      Func<HttpContextBase> lazyHttpContext)
                  {
                      this.dataContext = dataContext;
                      LazyHttpContext = lazyHttpContext;
              
                      var identityContext = new AppIdentityStoreContext(this.dataContext);
                      IdentityManager = new AppIdentityStoreManager(identityContext);
                      AuthenticationManager = new IdentityAuthenticationManager(
                          IdentityManager);
                  }
              
                  public IdentityAuthenticationManager AuthenticationManager
                  {
                      get;
                      protected set;
                  }
              
                  protected AppIdentityStoreManager IdentityManager { get; set; }
              
                  protected Func<HttpContextBase> LazyHttpContext { get; private set; }
              
                  public async Task<string> Signup(
                      string email,
                      string password,
                      bool requiresActivation)
                  {
                      var user = new User(email);
              
                      var token = await IdentityManager.CreateLocalUser(
                          user,
                          password,
                          requiresActivation);
              
                      return token;
                  }
              
                  public async Task<bool> SignIn(
                      string email,
                      string password,
                      bool persist)
                  {
                      return await AuthenticationManager.CheckPasswordAndSignIn(
                          LazyHttpContext(),
                          email,
                          password,
                          persist);
                  }
              }
              

The next three features are rather simple and easy as we have all the necessary things in place:


              public async Task<bool> Activate(string email, string token)
              {
                  var userId = await IdentityManager.GetUserIdForLocalLogin(email);
              
                  if (userId == null)
                  {
                      return false;
                  }
              
                  var activation = await dataContext.Tokens.FindAsync(userId);
              
                  if ((activation == null) || !activation.CanActivate(token))
                  {
                      return false;
                  }
              
                  activation.MarkActivated();
              
                  await dataContext.SaveChangesAsync();
              
                  return true;
              }
              
              public async Task<string> ForgotPassword(string email)
              {
                  var userId = await IdentityManager.GetUserIdForLocalLogin(email);
              
                  if (userId == null)
                  {
                      return null;
                  }
              
                  var token = await dataContext.Tokens.FindAsync(userId);
              
                  token.GenerateResetPasswordToken();
              
                  await dataContext.SaveChangesAsync();
              
                  return token.ResetPasswordToken;
              }
              
              public async Task<bool> ResetPassword(string token, string password)
              {
                  var reset = await dataContext.Tokens
                      .FirstOrDefaultAsync(t => t.ResetPasswordToken == token);
              
                  if (reset == null || reset.HasResetPasswordTokenExpired)
                  {
                      return false;
                  }
              
                  var user = await IdentityManager.Context.Users.Find(reset.UserId);
              
                  if (user == null)
                  {
                      return false;
                  }
              
                  var hasChanged = await IdentityManager.ChangePassword(
                      user.UserName,
                      password,
                      password);
              
                  if (hasChanged)
                  {
                      reset.ExpireResetPasswordToken();
                      await dataContext.SaveChangesAsync();
                  }
              
                  return hasChanged;
              }
              

The next part is integrating the external login support which does not require any modification, for GitHub OAuth2 I have also created a Owin authentication module like the other built-in modules, you can check the GitHub implementation over here and the nuget package.

Now, everything seems to run smoothly until I found out that UserName of User needs to be unique and seems silly as I myself have same user name in Facebook and GitHub. It turns out that uniqueness checking is in the ValidateEntity method of IdentityDbContext. All I have to overcome this issue is override this method:


              protected override DbEntityValidationResult ValidateEntity(
                  DbEntityEntry entityEntry,
                  IDictionary<object, object> items)
              {
                  return new DbEntityValidationResult(entityEntry, new DbValidationError[0]);
              }
              

But it introduces another issue, now we are allowing to have same user name for internal users and to restrict it we need a little modification in our CreateLocalUser method:

CreateLocalUser

              public async Task<string> CreateLocalUser(
                  IUser user,
                  string password,
                  bool requiresActivation)
              {
                  ValidateUser(user);
                  ValidatePassword(password);
              
                  if (await GetUserIdForLocalLogin(user.UserName) != null)
                  {
                      throw new IdentityException("User name already exists.");
                  }
              
                  if (!(await context.Users.Create(user)))
                  {
                      return null;
                  }
              
                  if (!(await context.Secrets.Create(
                      new UserSecret(user.UserName, password))))
                  {
                      return null;
                  }
              
                  if (!(await context.Logins.Add(
                      new UserLogin(user.Id, LocalLoginProvider, user.UserName))))
                  {
                      return null;
                  }
              
                  var token = new Token(user.Id, requiresActivation);
              
                  var dataContext = (DataContext)context.DbContext;
                  dataContext.Tokens.Add(token);
              
                  await dataContext.SaveChangesAsync();
              
                  return token.ActivationToken;
              }
              

And we are done, you will find the complete implementation in TextUml.

Few more observations:

  • Although there is an interface IUser but creating a custom User and implementing this interface does not work external user as the method GetUserIdentityClaims of IdentityAuthenticationManager needs an concrete class of User not IUser .
  • Both UserRoles and UserSecrets in the database stores the name instead of the Id which is quite unusual should be avoided.
  • You cannot have the same name entity class (e.g. User, Role etc.) that is already here, though it seems more of an EF issue.
  • Overall I think it is doing whole lot of things that it should not do and If your application logic varies from what it provides out of the box you are going to end up implementing the same.

That’s it for today.

refrence-:

http://kazimanzurrashid.com/posts/implementing-user-confirmation-and-password-reset-with-one-asp-dot-net-identity-pain-or-pleasure