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

Wednesday, May 30, 2012

ASP.NET MVC 3 - Effectively using Model metadata

In ASP.NET MVC 3, most developers might have observed the existence of the HTML helpers - DisplayForModel and EditorForModel. This post is just to give a hint on how effectively we can use the specified HTML helpers and hence we won't have any code Snippets here.

I frequently come across situations of creating proof of concept and several sample applications to evaluate certain implementations / metrics. In such cases, lot of time I really worried on creating a sample data entry / display page which consumes my time, because my core objective is to evaluate my target as early as possible. The EditorForModel HTML helper in ASP.NET MVC actually saves me lot of time and help me to just focus on my target while doing such POCs.

While doing so I thought some simple tweaks, like a way to represent display name, order ... for the property might help me to tune my sample page further. To achieve that, I got the help of DataAnnotations / Metadata.

Some sample requirements are
  • Need to hide a column - ScaffoldColumn(false)
  • Hidden value - HiddenInput
  • Display a different name - Display(Name = "Employee Name")
  • Display in a custom order - Display(Order=1)
  • Display format with different type than default - DataType(DataType.MultilineText)

Using these Metadata, we can, hide a property from creating HTML elements for that, create a hidden value element for a property, display a different name than that of the property, display in a custom order we need, specify what type of HTML element and what format can be used, etc.

Once you start explore other parameters of attributes and options, you can achieve lot of cases with minimal effort. Really its a time saving mechanism. If none of the options fits our scenario, then we can do the regular way.   

Monday, April 30, 2012

ASP.NET MVC 3 - Using Ninject for Dependency Injection


This post is to show how to implement Dependency Injection in ASP.NET MVC 3 application with simple steps. For Details on Dependency Injection (DI) please refer to my article here.

For the sake of simplicity and to understand the idea, I have simply specified all the classes in same project(web application here). In real time scenario this might extend to multiple class libraries based on the nature of the project.

In our example, we're targeting a Mark sheet creation with minimal and predefined data. MarkSheetController expects a MarksheetModel and the MarkSheetModel expects a MarkEvaluator which we're going to achieve with Constructor injection as follows.

Implementaiton Details

First we need to install the Ninject.MVC3 Nuget package using Nuget manager. For details on Nuget manager please verify my post here. Upon installing the package, a file called NinjectWebCommon.cs will get created under the folder called App_Start.  In the  static method called RegisterServices, add the statement to register the dependencies with Ninject container. Following Snippets are self explanatory to understand the concept.

Snippet 1: (App_Start/NinjectWebCommon.cs => NinjectWebCommon.RegisterServices())

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IMarkSheetModel>().To<MarkSheetModel>();
    kernel.Bind<IMarkEvaluator>().To<MarkEvaluator>();
}

In the above snippet I've registered with Ninject that MarkSheetModel concrete class is bound to IMarkSheetModel and MarkEvaluator concrete class is bound to IMarkEvaluator interface. Based on this Ninject resolves the dependency by creating instance for the respective concrete class and pass it in the place of the related interface specification. Following snippet shows how we're making use of constructor injection to achieve that.

Snippet 2: (MarkSheetController - note the IMarkSheetModel parameter in the constructor)

public class MarkSheetController : Controller
{
    private IMarkSheetModel model;


    public MarkSheetController(IMarkSheetModel modelParam)
    {
        model = modelParam;
    }

    //
    // GET: /MarkSheet/

    public ActionResult Index()
    {
        model.LoadDetails();
        return View(model);
    }

}

Snippet 3: (MarkSheetController - note the IMarkEvaluator parameter in the constructor)

public class MarkSheetModel : IMarkSheetModel
{
    private IMarkEvaluator evaluator;

    public string StudentId { get; set; }
    public string StudentName { get; set; }
    public IEnumerable<Subject> SubjectList { get; set; }
    public int Total { get; private set; }
    public decimal Average { get; private set; }
    public string Grade { get; private set; }
    
    public MarkSheetModel(IMarkEvaluator evaluatorParam)
    {
        evaluator = evaluatorParam;
    }

    public void LoadDetails()
    {
        this.StudentId = "S1001";
        this.StudentName = "Sample";

        this.SubjectList = new List<Subject> { new Subject{ SubjectId="Sub0001", SubjectName ="Sub 1", Score = 78},
        new Subject{ SubjectId="Sub0002", SubjectName ="Sub 2", Score = 84},
        new Subject{ SubjectId="Sub0003", SubjectName ="Sub 3", Score = 72},
        new Subject{ SubjectId="Sub0004", SubjectName ="Sub 4", Score = 69}};

        this.Total = this.evaluator.CalculateTotal(this.SubjectList);
        this.Average = this.evaluator.CalculateAverage(this.SubjectList);
        this.Grade = this.evaluator.CalculateGrade(this.SubjectList);
    }

}

public interface IMarkSheetModel
{
    void LoadDetails();
    IEnumerable<Subject> SubjectList { get; set; }
    string StudentId { get; set; }
    string StudentName { get; set; }
}

public class Subject
{
    public string SubjectId { get; set; }
    public string SubjectName { get; set; }
    public int Score { get; set; }
}

Snippet 4:

public class MarkEvaluator : IMarkEvaluator
{
    public int CalculateTotal(IEnumerable<Subject> subjectList)
    {
        return subjectList.Sum(su => su.Score);
    }

    public decimal CalculateAverage(IEnumerable<Subject> subjectList)
    {
        return Convert.ToDecimal(CalculateTotal(subjectList)) / subjectList.Count();
    }

    public String CalculateGrade(IEnumerable<Subject> subjectList)
    {
        decimal averageScore = CalculateAverage(subjectList);

        if (averageScore > 80)
        {
            return "Grade A";
        }
        else if (averageScore > 70)
        {
            return "Grade B";
        }
        else if (averageScore > 60)
        {
            return "Grade C";
        }
        else
        {
            return "Grade D";
        }
    }
}

public interface IMarkEvaluator
{
    decimal CalculateAverage(IEnumerable<Subject> subjectList);
    string CalculateGrade(IEnumerable<Subject> subjectList);
    int CalculateTotal(IEnumerable<Subject> subjectList);
}


While executing the above snippets, the constructor of the MarkSheetController and MarkSheetModel is supplied with the respective instance.

References:
https://github.com/ninject/ninject.web.mvc/wiki/MVC3


Friday, March 30, 2012

ASP.NET MVC 3 - Converting / Serializing .Net objects into JSON format in View


In ASP.NET MVC often we might need to use / manipulate Model objects or its property inside the javascript. In order to achieve that, we usually try to serialize the .Net object and store it in a javascript variable which will then be accessed further in javascript.

Using Razor view engine, we can achieve this easily. In the following, I'll explain two approaches with a simple View(.cshtml) snippet to understand the concept. 

Approach 1: (Using Json.Encode(...))

Snippet 1: (Index.cshtml)

@model Web.POC.Models.FeedModel
@{
    ViewBag.Title = "Feed viewer";
}

<script type="text/javascript">
    var entries = @Html.Raw(Json.Encode(Model.FeedEntries));    
</script>


Approach 2: (Using JavaScriptSerializer)

Snippet 2: (Index.cshtml)

@model Web.POC.Models.FeedModel
@{
    ViewBag.Title = "Feed viewer";
}

@{
   System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
}
<script type="text/javascript">
    var entries = @Html.Raw(serializer.Serialize(Model.FeedEntries));    
</script>


Assumptions:

As specified, the above snippets are just to understand the concept. In that, consider that we're having a model "FeedModel" which holds a property called "FeedEntries" of some custom type which we're trying to convert into JSON object.

Also note that we need to use the HTML.Raw() to indicate that the output should not be HTML encoded.


Monday, February 6, 2012

ASP.NET MVC 3 - Accessing Session inside Task of AsyncController

Before getting into the core of this post, let us have a quick look at Async controller. The base thing that we need to understand is that, Async controllers are implemented to achieve the efficient service of the incoming requests rather than faster processing of individual request. Scenarios like the case of having a network call which consumes some time might block the thread (that is processing the current request) from processing other requests. For understanding the need for using the AsyncController, there exists several articles over the web. One such nicely explained article is here.

In order to implement the Async controller, we need to do the following.
Derive the controller from AsyncController. 
Specify an <ActionName>Async and <ActionName>Completed methods for each Actions, where <ActionName>Async is of return type void and the relevant <ActionName>Completed returns the ActionResult.
Usually the network calls will be made in the <ActionName>Async method and the resultant is passed over to the <ActionName>Completed method as arguments.

Above specified info are fine enough to implement the Async controller. Apart from that, we also need to think of effectively handling the network calls and other time consuming items inside the <ActionName>Async method. In real case, usually we'll call the method in Model / ViewModel which then initiates the network call,  call to the Service Locator or Service Agent. For achieving this, we can alter the Model / ViewModel to expose the relevant methods async mode. Instead we can also seek help from the .Net built in library named Task Parallel Library (TPL). Instead of explaining further, I directly dive into the code sample from which you can easily understand the base.

Snippet 1:

public void IndexAsync(int id)
{
    AsyncManager.OutstandingOperations.Increment();

    Task.Factory.StartNew(() => {
        InfoViewModel moreViewModel = new InfoViewModel();
        InfoViewModel.MoreModel moreModel = moreViewModel.GetDetails(id);

        AsyncManager.Parameters["moreModel"] = moreModel;
        AsyncManager.OutstandingOperations.Decrement();
    });
    
}

public ActionResult IndexCompleted(InfoViewModel.MoreModel moreModel)
{
    return View("Info", moreModel);
}

The AsyncManager related operations specified in the above code helps us to achieve handling of  aysnc operations effectively. For example, the Increment(), Decrement() methods and Parameters property helps the controller to identify, when to make the call to relevant <ActionName>Completed method with specific parameters. As you guess, the Task.Factory.StartNew(Action) will be executed in a separate thread and in the mean time, statements following it got executed and waits until the AsyncManager.OutstandingOperations becomes zero after which <ActionName>Completed gets called.

OK, now comes the core of the post. Think of a situation where we need to use access the Session values inside the method of Model / ViewModel which is initiated from Task.Factory.StartNew(Action).  Since the Task is executed in a separate thread, that thread won't hold the HttpContext that is System.Web.HttpContext.Current will be null. To make it work, we can assign the System.Web.HttpContext.Current with the HttpContext got from ControllerContext as follows.

Snippet 2:

System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context;


Please note that the above specified fix is just a workaround. For such scenarios, we need to alter the method in the Model in such a way to receive the value retrieved from session as one of the parameter. 

As we might use this repeatedly, we can create a base class and make use it in places wherever required.

Snippet 3: (BaseAsyncController) 

public class BaseAsyncController : AsyncController
{
    protected void StartContextEnabledTask(Action action)
    {
        Task.Factory.StartNew(() => {
            System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context;
            action();
        });
    }
}

Snippet 4: (Full Implementation)

public class InfoController : BaseAsyncController
{
    public void IndexAsync(int id)
    {
        AsyncManager.OutstandingOperations.Increment();
    
        StartContextEnabledTask(() => {
            InfoViewModel moreViewModel = new InfoViewModel();
            InfoViewModel.MoreModel moreModel = moreViewModel.GetDetails(id);
    
            AsyncManager.Parameters["moreModel"] = moreModel;
            AsyncManager.OutstandingOperations.Decrement();
        });
        
    }
    
    public ActionResult IndexCompleted(InfoViewModel.MoreModel moreModel)
    {
        return View("Info", moreModel);
    }    
}

References:
http://www.aaronstannard.com/post/2011/01/06/asynchonrous-controllers-ASPNET-mvc.aspx
http://msdn.microsoft.com/en-us/library/dd537609.aspx
http://craigcav.wordpress.com/2010/12/23/asynchronous-mvc-using-the-task-parallel-library/

Saturday, October 29, 2011

ASP.NET MVC 3 - Representing contents in Razor View

The Razor view engine in ASP.NET MVC 3, throws error when we specify the content block directly without enclosing it in tags especially inside the coding constructs like if, for loop and so on.

Following Snippet throws error
@if(condition) {
    Any direct content.......
}


In such cases, developers usually specify tags like <span> as a workaround in order to specify the contents. But there exists two ways for directly represent this case.
  1. @: - for indicating the characters following it are content items and usually used for representing single line content.
  2. <text>....</text> - entire content block is enclosed within the <text>....</text> element and usually used for representing multi line contents.

@if(condition) {
    <text>Multi line statement 1
    Multi line statement 1
    ..................
    Multi line statement n</text>
}


@if(condition) {
    @:single line content goes here....
}


This is a straight forward feature but unexposed to several developers. It is simple but effective.

Sunday, October 9, 2011

ASP.NET MVC - Html.Partial vs Html.RenderPartial

RenderPartial writes the result directly to the response, technically speaking, directly into the calling object's TextWriter.

Partial on the other hand returns the HTML markup as string, which buffers the content. It achieves by creating and using a separate TextWriter.

Syntactic representation:
RenderPartial should be used inside a code block (obviously followed by a semicolon).

@{
    Html.RenderPartial("TestPartialView1");
}

Partial can be used directly as it returns the HTML markup as string.

@Html.Partial("TestPartialView1")

Usage:
Considering the performance RenderPartial is a bit faster and hence developers prefer using it inside the looping constructs and related scenarios.

Preference of Partial prevails in the case of regular syntax usage(meaning - uniform syntax usage as we don't need to wrap inside the code block) and if we need to perform any manipulation with the resultant HTML markup string.
Creative Commons License
This work by Tito is licensed under a Creative Commons Attribution 3.0 Unported License.