Using the Features of ASP.NET MVC 3 Futures

    Introduction:



          ASP.NET MVC 3 includes a bunch of new features that can help you to develop Rich Internet Application(RIA) easily. In addition to these new features, you can also use the features of ASP.NET MVC 3 Futures. ASP.NET MVC 3 Futures includes a bunch of features which may become the part of ASP.NET MVC in future. But you don't have to wait for the future version of ASP.NET MVC to use these features.  In this article, I will show you the features of ASP.NET MVC 3 Futures. I will also show you how to use these features in ASP.NET MVC 3 application. 

 

    Description:

          First of all, you need to download the ASP.NET MVC 3 Futures from Codeplex. Then, create an ASP.NET MVC 3 application and add a reference of Microsoft.Web.Mvc assembly.

 

    CachedDataAnnotationsModelMetadataProvider:

 

           When ASP.NET MVC 3 RC 2 released, it includes a model meta-data provider called CachedDataAnnotationsModelMetadataProvider. This model meta-data provider intended for improving the overall application performance. But this provider has been removed from ASP.NET MVC 3 RTM because it introduced some bugs. Now you can use this provider in ASP.NET MVC 3 application via ASP.NET MVC 3 Futures. For using this provider, just open global.asax file and add the following line in the Application_Start method, 

 

            ModelMetadataProviders.Current = new CachedDataAnnotationsModelMetadataProvider();

 

    New Validation Attributes:

 

          In ASP.NET MVC 3, there is no built-in support for validating email, URL, credit card and file extension. However, through ASP.NET MVC 3 Futures, you can add these validations into your ASP.NET MVC 3 application. For details, see New Validation Attributes in ASP.NET MVC 3 Future.

 

    Model Copier:

 

          In ASP.NET MVC, you often need to copy(or map) the members of your domain model into view model classes, and vice-versa. One way to do this is to use the built-in Object.MemberwiseClone method. But this method has some limitations, such as, you have to do deep copy yourself which is not easy, etc. ASP.NET MVC 3 Futures makes it easy to copy the model members. Here is an example that shows you how to use this feature,

 

            namespace UsingFeaturesASPNETMVC3Futures.Controllers
            {
                public class ModelCopierController : Controller
                {
                    public ActionResult Index()
                    {
                        var student = new Student { Age=27, Name="Imran Baloch" };
                        var studentViewModel = new StudentViewModel();
                        ModelCopier.CopyModel(student,studentViewModel);
                        return View(studentViewModel);
                    }
                }
            }
            namespace UsingFeaturesASPNETMVC3Futures.ViewModels
            {
                public class StudentViewModel
                {
                    public int Age { get; set; }

                    public string Name { get; set; }
                }
            }
            namespace UsingFeaturesASPNETMVC3Futures.DomainModels
            {
                public class Student
                {
                    public int Age { get; set; }

                    public string Name { get; set; }
                }
            }

 

          This is important to note that ModelCopier will only copy the class properties, not the class fields. AutoMapper is recommended for complex mappings.

 

    Html Helpers with Optional Parameters:

 

          HTML helpers are methods that are used to render HTML elements quickly. Currently, the only way to pass attributes to HTML helper methods is through a dictionary or anonymous object. ASP.NET MVC 3 Futures has HTML helper methods which accept their legal attributes as optional parameter. In order to use these HTML helpers, you just need to import Microsoft.Web.Mvc.Html namespace in web.config,     

 

            <add namespace="Microsoft.Web.Mvc.Html"/>

 

          

 

 

          Note that during importing Microsoft.Web.Mvc.Html namespace in web.config, you also need to remove System.Web.Mvc.Html namespace because all HTML helpers are recreated in Microsoft.Web.Mvc.Html.HtmlHelperExtensions class. The benefit of using these new HTML helpers is that now these helpers will only allow legal attributes of an HTML element.

 

    AjaxOnly Action Method Selector:

 

          Action method selector allows you to select or ignore an action method under certain conditions. Sometimes, you need to only allow an action to execute if the request is an ajax request. Using ASP.NET MVC 3 Futures, you can decorate an action method with AjaxOnly attribute to meet this behaviour. Here is some code that shows you how to use this feature, 

 

            [AjaxOnly]
            public ActionResult MyAjaxMethod()
            {
                return Content("My Ajax Method Contents.");
            }

 

 

 

    Value Providers:

 

          ASP.NET MVC 3 includes value provider for Form, QueryString, Route, HttpFileCollection, ChildAction and Json. ASP.NET MVC 3 Futures has some more value providers. These value providers includes ServerVariables, Session, TempData and Cookie. These value providers allows you to access session, server variables, temp data and cookie via action method parameters. For seeing these value providers in action, first you need to register them in Application_Start method,

 

            ValueProviderFactories.Factories.Add(new ServerVariablesValueProviderFactory());
            ValueProviderFactories.Factories.Add(new SessionValueProviderFactory());
            ValueProviderFactories.Factories.Add(new TempDataValueProviderFactory());
            ValueProviderFactories.Factories.Add(new CookieValueProviderFactory());

 

          Next, you need to add a new controller with the following code,

 

            public class NewValueProvidersController : Controller
            {
            	public ActionResult Index(string HTTP_USER_AGENT, string Name, string SName, string FullName)
            	{
                    Session["Name"] = "Imran";
                    TempData["SName"] = "Baloch";
                    Response.Cookies.Add(new HttpCookie("FullName", "Imran Baloch"));
                    return Content("");
            	}
            }

 

          In the above code, you are accessing session, server variables, temp data and cookie via action method parameters.

 

    CookieTempDataProvider:

 

          TempData allows you to store data between the current request and the request in which it is read. By default, TempData is stored in the session, but you can store it in a custom data store. Using ASP.NET MVC 3 Futures, you can replace TempData’s underlying data store with cookie. Here is an example that shows you how to store TempData inside a cookie,

 

            public class CookieTempDataProviderController : Controller
            {
            	public ActionResult Index()
            	{
                    if (TempData["Test"] == null)
                        TempData["Test"] = "Not Null";
                    return Content("");
            	}

            	protected override void Initialize(RequestContext requestContext)
            	{
                    base.Initialize(requestContext);
                    TempDataProvider = new CookieTempDataProvider(requestContext.HttpContext);
            	}
            }

 

 

    DynamicViewPage:

 

          There are times when you just need to pass a very simple model to your view. In these cases, you may not want to bother a new view model. Rather, you can create an anonymous object and pass this model to your view. DynamicViewPage class allows you to do that easily. Here is an example,

 

            public class DynamicViewPageController : Controller
            {
                public ActionResult Index()
                {
                    return View(new { FirstName="Imran", LastName="Baloch"});
                }
            }

 

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

            <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
                Index
            </asp:Content>

            <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

                <h2>Index</h2>
                <%: Model.FirstName %>
                <%: Model.LastName %>
                </asp:Content>

 

          Note that I am inheriting the view with Microsoft.Web.Mvc.DynamicViewPage class. This is necessary, otherwise you will get an RuntimeBinderException exception.

 

    MvcDiagnostics:

 

          ASP.NET MVC 3 Futures contains a web form page called MvcDiagnostics.aspx. This page shows you the information about your application environment(OS name, Framework version, etc) and information about ASP.NET MVC assembly, ASP.NET MVC Futures assembly and all assemblies loaded inside the current application domain. This page also shows you an error, if ASP.NET MVC and ASP.NET MVC Futures assemblies are incompatible. To use this, just drop the MvcDiagnostics.aspx file into your application root directory and then navigate to /MvcDiagnostics.aspx. For details, see Diagnosing ASP.NET MVC Problems

 

    SerializationExtensions:

 

          Many times you need to persist/share/keep data across requests. There are many ways to do this. One way is to serialize your data into a hidden form field. Later, when the browser posts the form back, you can retrieve your data by deserializing the incoming hidden form value. Let's see an example to clearly see how it works,

 

            namespace UsingFeaturesASPNETMVC3Futures.Controllers
            {
                public class SerializationExtensionsController : Controller
                {
                    public ActionResult Index()
                    {
                        ViewData["Industry"] = new Industry { Name = "Alex Solutions", Address="Karachi, Pakistan" };
                        return View(new Job { Title = "Software Engineer", Level = "Senior" });
                    }

                    [HttpPost]
                    public ActionResult Index(Job job, [Deserialize] Industry industry)
                    {
                        return Index();
                    }
                }
            }
            namespace UsingFeaturesASPNETMVC3Futures.Models
            {
                public class Job
                {
                    public string Title { get; set; }

                    public string Level { get; set; }
                }
        
                public class Industry
                {
                    public string Name { get; set; }

                    public string Address { get; set; }
                }
            }

 

            @using Microsoft.Web.Mvc
            @using UsingFeaturesASPNETMVC3Futures.Models

            @model UsingFeaturesASPNETMVC3Futures.Models.Job

            @{
                ViewBag.Title = "Index";
            }

            <h2>Index</h2>

            <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
            <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

            @using (Html.BeginForm()) {
                @Html.ValidationSummary(true)
                <fieldset>
                    <legend>Job</legend>

                    <div class="editor-label">
                        @Html.LabelFor(model => model.Title)
                    </div>
                    <div class="editor-field">
                        @Html.EditorFor(model => model.Title)
                        @Html.ValidationMessageFor(model => model.Title)
                    </div>

                    <div class="editor-label">
                        @Html.LabelFor(model => model.Level)
                    </div>
                    <div class="editor-field">
                        @Html.EditorFor(model => model.Level)
                        @Html.ValidationMessageFor(model => model.Level)
                    </div>
                    @Html.Serialize("Industry",ViewData["Industry"] as Industry)
                    <p>
                        <input type="submit" value="Save" />
                    </p>
                </fieldset>
            }

            <div>
                @Html.ActionLink("Back to List", "Index")
            </div>

 

 

    Action Results:

 

          In ASP.NET MVC, the return type of a controller action called action result. An action result is responsible for writing the response. Several types of action results are supported in ASP.NET MVC 3 including ViewResult, RedirectResult, ContentResult, etc. ASP.NET MVC 3 Futures includes some more action results. These action results include an action result that uses DataContractSerializer class to render an object to the XML format(DataContractXmlActionResult), an action result that uses DataContractJsonSerializer class to render an object to the JSON format(DataContractJsonActionResult), an action result that uses Atom 1.0 entry format to render a SyndicationItem(AtomEntryActionResult), an action result that uses Atom 1.0 feed format to render a SyndicationFeed(AtomFeedActionResult), an action result that uses ServiceDocument format to render a ServiceDocument(AtomServiceDocumentActionResult),  an action result that uses specified format to return the response(MultiFormatActionResult) and an action result for returning HTTP errors that result from performing operations on resources(ResourceErrorActionResult).  Here is an example that leverages these new action results,

 

            namespace UsingFeaturesASPNETMVC3Futures.Models
            {
                [DataContract]
                public class Person
                {
                    [DataMember]
                    public string FirstName { get; set; }

                    [DataMember]
                    public string LastName { get; set; }
                }

            }
            namespace UsingFeaturesASPNETMVC3Futures.Controllers
            {
                public class NewActionResultsController : Controller
                {
                    public ActionResult Index()
                    {
                        return View();
                    }

                    public ActionResult AtomEntryActionResultAction()
                    {
                        var item = GetAtomEntry();
                        return new AtomEntryActionResult(item);
                    }

                    public ActionResult AtomFeedActionResultAction()
                    {
                        var feed = GetAtomFeed();
                        return new AtomFeedActionResult(feed);
                    }

                    public ActionResult AtomServiceDocumentActionResultAction()
                    {
                        var doc = GetAtomService();
                        return new AtomServiceDocumentActionResult(doc);
                    }

                    public ActionResult DataContractJsonActionResultAction()
                    {
                        return new DataContractJsonActionResult(new Person(){ FirstName = "Imran", LastName = "Baloch" });
                    }

                    public ActionResult DataContractXmlActionResultAction()
                    {
                        return new DataContractXmlActionResult(new Person() { FirstName = "Imran", LastName = "Baloch" });
                    }

                    public ActionResult MultiFormatActionResultAction()
                    {
                        return new MultiFormatActionResult(new Person() { FirstName = "Imran", LastName = "Baloch" }, new ContentType("application/xml"));
                    }

                    public ActionResult ResourceErrorActionResultAction()
                    {
                        return new ResourceErrorActionResult(new HttpException(400,""),new ContentType("text/html"));
                    }

                    #region Private Methods
        
                    private static SyndicationItem GetAtomEntry()
                    {
                        //Code copied from, http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationitem.aspx
                        SyndicationItem item = new SyndicationItem("My Item", "This is some content", new Uri("http://SomeServer/MyItem"), "Item ID", DateTime.Now);
                        item.Authors.Add(new SyndicationPerson("jesper@contoso.com", "Jesper Aaberg", "http://contoso/jesper"));
                        item.Categories.Add(new SyndicationCategory("Category One"));
                        item.Contributors.Add(new SyndicationPerson("lene@contoso.com", "Lene Aaling", "http://contoso/lene"));
                        item.Copyright = new TextSyndicationContent("Copyright 2007");
                        item.Links.Add(new SyndicationLink(new Uri("http://OtherServer/Item"), "alternate", "Alternate Link", "text/html", 1000));
                        item.PublishDate = new DateTime(2007, 2, 23);
                        item.Summary = new TextSyndicationContent("this is a summary for my item");
                        XmlQualifiedName xqName = new XmlQualifiedName("itemAttrib", "http://FeedServer/tags");
                        item.AttributeExtensions.Add(xqName, "ItemAttribValue");
                        return item;
                    }

                    private static SyndicationFeed GetAtomFeed()
                    {
                        //Code copied from, http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationitem.aspx
                        var item = GetAtomEntry();
                        SyndicationFeed feed = new SyndicationFeed();
                        Collection<SyndicationItem> items = new Collection<SyndicationItem>();
                        items.Add(item);
                        feed.Items = items;
                        return feed;
                    }

                    private static ServiceDocument GetAtomService()
                    {
                        //Code copied from, http://msdn.microsoft.com/en-us/magazine/dd569753.aspx
                        ServiceDocument doc = new ServiceDocument();
                        doc.BaseUri = new Uri("http://localhost");
                        List<ResourceCollectionInfo> resources = new List<ResourceCollectionInfo>();
                        ResourceCollectionInfo mainBlog = new ResourceCollectionInfo("MSDNMagazine", new Uri("feed", UriKind.Relative));
                        mainBlog.Accepts.Add("application/atom+xml;type=entry");
                        resources.Add(mainBlog);
                        ResourceCollectionInfo mainPictures = new ResourceCollectionInfo("Pictures", new Uri("pictures", UriKind.Relative));
                        mainPictures.Accepts.Add("image/png");
                        mainPictures.Accepts.Add("image/jpeg");
                        mainPictures.Accepts.Add("image/gif");
                        resources.Add(mainPictures);
                        Workspace main = new Workspace("Main", resources);
                        doc.Workspaces.Add(main);
                        return doc;
                    }

                    #endregion
                }
            }

  

    Action Filters:

 

          ASP.NET MVC allows you to interfere in the execution pipeline of an action method through Action Filters. This means that you can do something before and after the action method executes. ASP.NET MVC 3 includes ChildActionOnly, OutputCache, HandleError, Authorize, and several other action filters. ASP.NET MVC 3 Futures contains an action filter for setting the content type of the response(ContentType), an action filter that supports multiple formats(HTML, XML, JSON etc), HTTP method based dispatch and HTTP error handling(WebApiEnabled) and an action filter that copy the action method parameters to AsyncManager.Parameters(CopyAsyncParameters). Here is an example that shows you how you can use these new action filters,     

 

            namespace UsingFeaturesASPNETMVC3Futures.Models
            {
                public class Ground
                {
                    public string Name { get; set; }

                    public int Width { get; set; }

                    public int Height { get; set; }
                }
            }
            namespace UsingFeaturesASPNETMVC3Futures.Controllers
            {
                public class NewActionFiltersController : AsyncController
                {
                    public ActionResult Index()
                    {
                        return View();
                    }

                    [CopyAsyncParameters]
                    public void CopyAsyncParametersAsync(string name)
                    {
                        // Here, name = AsyncManager.Parameters["name"]
                    }

                    public ActionResult CopyAsyncParametersCompleted(string name)
                    {
                        return Content("Plain");// Without CopyAsyncParameters, name will be null
                    }

                    [WebApiEnabled]
                    public ActionResult WebApiEnabledAction()
                    {
                        // With WebApiEnabled, this same action can return response in Html, Xml, Json format
                        // For Xml response, append ?format=Xml and for Json response, append ?format=Json 
                        var ground = new Ground { Name = "Princeton Stadium", Width = 650, Height = 531 };
                        return View(ground);
                    }

                    [ContentType("text/plain")]
                    public ActionResult ContentTypeAction()
                    {
                        return Content("Plain","text/html");// ContentType will override text/html
                    }
                }
            }

 

          The CopyAsyncParameters attribute will synchronize the CopyAsyncParametersAsync action method parameters with AsyncManager.Parameters. The ContentType attribute allows you to set the content-type of the response. The framework will use the specified content-type, regardless what the action method returns. The WebApiEnabled attribute allows you to return the response of an action method in various format. WebApiEnabled was originally the part of Rest For ASP.NET MVC SDK. Now you can use it through ASP.NET MVC 3 Futures. In addition to WebApiEnabled, you can also use other features of Rest For ASP.NET MVC SDK like ResourceControllerFactory(as a base controller factory to make your application RESTful) and ResourceModelBinder(as a inner model binder with support for binding to other formats). This future assembly also contains some HTML, AJAX and URL helpers, which are useful for REST scenario. It also include RouteCollectionExtensions, which adds the routes to enable RESTful routing of requests to specified controller.    

   

    SkipBindingAttribute:

 

          The SkipBinding attribute allows you to skip the model binding process for certain action method parameters. This may be helpful for you if you are using some consistent action method parameters and these parameters are not interested in model binding process at all.        

 

            namespace UsingFeaturesASPNETMVC3Futures.Models
            {
                public class Employee
                {
                    public string Name { get; set; }

                    public string Department { get; set; }
                }
            }

            namespace UsingFeaturesASPNETMVC3Futures.Controllers
            {
                public class SkipBindingController : Controller
                {
                    public ActionResult Index()
                    {
                        return View();
                    }

                    [HttpPost]
                    public ActionResult Index([SkipBinding]Employee employee1, Employee employee2)
                    {
                        // Here, employee2 parameter will be model binded while employee1 not
                        return View();
                    }
                }
            }

   

    Helpers and Extensions:

 

          ASP.NET MVC 3 Futures also contains some nice helpers and extensions. This includes,

          Script and Css HTML helpers make it easy for you to include css and script files in your view,

 

            @Html.Script("~/Scripts/jquery-1.4.4.js")
            @Html.Css("~/Content/Site.css")

 

          Name Extensions allows you to get the Id and Name of an expression,     

 

            @Html.Id("Name")
            @Html.Name("Name")
            @Html.IdFor(m => m.Name)
            @Html.NameFor(m => m.Name)
            @Html.IdForModel()
            @Html.NameForModel()

 

          You can use ImageExtensions to easily render HTML img element. You can use MailToExtensions to create a mailto link. You can use ButtonsAndLinkExtensions to generate HTML button, submit button and submit image element,

 

            @Html.Image("~/loading.gif")
            @Html.Mailto("Imran Baloch","imran_ku07@yahoo.com")
            @Html.Button("btnOK","OK",HtmlButtonType.Button)
            @Html.SubmitButton("btnSubmit","Submit")
            @Html.SubmitImage("imgSubmit", "~/loading.gif")

 

          With RadioListExtensions, you can easily create a group of radio buttons. Here is an example of using RadioButtonList HTML helper,

 

            @{
                var sports = new[] { 
                                        new{ Name = "Cricket", ID = 1 },
                                        new{ Name = "FootBall", ID = 2 },
                                        new{ Name = "Hockey", ID = 3 },
                                        new{ Name = "Tennis", ID = 4 }
                                    }.ToList();
                var selectList = new SelectList(sports, "ID", "Name", 3);
                MvcHtmlString[] radioButtons = Html.RadioButtonList("Sport", selectList);
                 for (int i = 0; i < radioButtons.Length; i++) { 
                     @(sports[i].Name+": ") @radioButtons[i]
                } 
            }

 

          ViewExtensions has a generic Html.RenderAction<T> overload, LinkExtensions contains some generic Html.ActionLink<T> overloads, FormExtensions contains some generic Html.BeginForm<T> overloads, ControllerExtensions contains some generic Html.RedirectToAction<T> overloads. These overloads lets you to use a strongly typed lambda expression to reference a target action. Here is an example which uses these strongly typed extensions, 

 

            @{
                using (Html.BeginForm<NewActionFiltersController>(action => action.ContentTypeAction()))
                {
                    Html.RenderAction<HelpersAndExtensionsController>(action => action.Temp());
                    <br />
                    var act = Html.ActionLink<NewActionFiltersController>(action => action.ContentTypeAction(), "ContentTypeAction");
                    @act
                }
            }

 

            public ActionResult Index()
            {
                return View();
            }
            public ActionResult TempAction()
            {
                // This is the Strongly Typed RedirectToAction
                return this.RedirectToAction(action => action.Index());
            }

 

          AsyncManagerExtensions contains a RegisterTask method which allows you to register tasks by passing the target Begin and End methods. These tasks are then automatically handles the synchronization. The code below will show you how to use this extension,

 

            public void AsynchronousActionAsync()
            {
                GetWeatherAsync();
                GetLatitudeAndLongitudeAsync();
                GetNewsAsync();
            }

            private void GetWeatherAsync()
            {
                WebRequest webRequest = WebRequest.Create("http://www.google.com/ig/api?weather=Karachi");
                AsyncManager.RegisterTask(callback => webRequest.BeginGetResponse(callback, null), ar =>
                {
                    var webResponse = webRequest.EndGetResponse(ar);
                    StreamReader stream = new StreamReader(webResponse.GetResponseStream());
                    string xml = stream.ReadToEnd();
                    XDocument doc = XDocument.Parse(xml);
                    var current_conditions = doc.Descendants("weather").Descendants("current_conditions").First();
                    AsyncManager.Parameters["condition"] = current_conditions.Element("condition").Attribute("data").Value;
                    AsyncManager.Parameters["temp_f"] = current_conditions.Element("temp_f").Attribute("data").Value;
                    AsyncManager.Parameters["temp_c"] = current_conditions.Element("temp_c").Attribute("data").Value;
                    AsyncManager.Parameters["humidity"] = current_conditions.Element("humidity").Attribute("data").Value;
                    AsyncManager.OutstandingOperations.Decrement();
                }
                );
            }

            private void GetLatitudeAndLongitudeAsync()
            {
                WebRequest webRequest = WebRequest.Create("http://where.yahooapis.com/geocode?q=Karachi");
                AsyncManager.RegisterTask(callback => webRequest.BeginGetResponse(callback, null), ar =>
                {
                    var webResponse = webRequest.EndGetResponse(ar);
                    StreamReader stream = new StreamReader(webResponse.GetResponseStream());
                    string xml = stream.ReadToEnd();
                    XDocument doc = XDocument.Parse(xml);
                    var result1 = doc.Descendants("ResultSet").Descendants("Result").First();
                    AsyncManager.Parameters["latitude"] = result1.Element("latitude").Value;
                    AsyncManager.Parameters["longitude"] = result1.Element("longitude").Value;
                }
                );
            }

            private void GetNewsAsync()
            {
                WebRequest webRequest = WebRequest.Create("http://search.yahooapis.com/NewsSearchService/V1/newsSearch?query=karachi&results=1&appid=yahoodemo");
                AsyncManager.RegisterTask(callback => webRequest.BeginGetResponse(callback, null), ar =>
                {
                    var webResponse = webRequest.EndGetResponse(ar);
                    StreamReader stream = new StreamReader(webResponse.GetResponseStream());
                    string xml = stream.ReadToEnd();
                    XDocument doc = XDocument.Parse(xml);
                    var result1 = doc.Descendants().First().Descendants().First();
                    AsyncManager.Parameters["NewsTitle"] = result1.Elements().First().Value;
                }
                );
            }

            public ActionResult AsynchronousActionCompleted(string condition, string temp_f, string temp_c, string humidity, string latitude, string longitude, string NewsTitle)
            {
                ViewData["condition"] = condition;
                ViewData["temp_f"] = temp_f;
                ViewData["temp_c"] = temp_c;
                ViewData["humidity"] = humidity;
                ViewData["latitude"] = latitude;
                ViewData["longitude"] = longitude;
                ViewData["NewsTitle"] = NewsTitle;
                ViewData["Title"] = "Asynchronous Action";
                return View();
            }

   

          The above code uses the same example presented at here with a small difference: now AsyncManager.RegisterTask method is used, so no need to use AsyncManager.OutstandingOperations.Increment(or Decrement) method and no need to synchronize your calls because now AsyncManager.RegisterTask method will do this for you.

 

           With AreaHelpers, you can get the area name of the current request. IEnumerableExtensions contains an AsSerializable<T> extension method which allows an IEnumerable<T> type to be serialized by DataContractSerilizer.  Here is an example of using this,

 

            @{
                var persons = new List<Person> { new Person { FirstName = "Cricket" }, new Person { FirstName = "FootBall" } }.AsQueryable().AsSerializable();
                // Without AsSerializable(), you will get an exception
                XmlWriterSettings settings = new XmlWriterSettings();
                DataContractSerializer dcs = new DataContractSerializer(persons.GetType());
                var sWriter = new StringWriter();
                using (XmlWriter writer = XmlWriter.Create(sWriter))
                {
                    dcs.WriteObject(writer, persons);
                    writer.Flush();
                }
            }
            @sWriter

 

           Note that, if I remove AsSerializable() method from the above code then you will get an exception.     

 

        Summary:

          ASP.NET MVC 3 Futures comes with a bunch of features that can make your application run faster, easier to develop, more productive and maintainable. In this article, I showed you most of the features of ASP.NET MVC 3 Futures. I also showed you how to use these features in your application. I am attaching a sample application. Hopefully you will enjoy this article too. 

 

8 Comments

  • Hello Imran,
    Nice post. Will these features be available in MVC 3 after in future, or we have to enable them manually?
    Just a small fix:

    // Here, employee2 parameter will be model binded while employee2 not

    Maybe the "employee1" object will be skipped.

  • @Vest,
    There is no guarantee that which and what features will become the part of core ASP.NET MVC.

    You are correct, this was a typo. Corrected now.

  • Very nice post! MVC Futures is one of those things I recommend to everyone doing MVC development. The lambda-based extensions alone are worth the price of admission. :-)

  • Hi Imran, I have one requirement on using a Modeldataproviders, I want to make a field visible/invisible. can you please help me on that. thanks

  • @ak_netchat,
    It is bext to ask these type of questions in stackoverflow.com or forums.asp.net/1146.aspx

  • I do not drop many remarks, however I read a few of the remarks here
    Using the Features of ASP.NET MVC 3 Futures - Imran Baloch's Blog
    .
    I actually do have 2 questions for you if it's okay. Is it only me or does it seem like a few of the comments look as if they are coming from brain dead folks? :-P And, if you are posting at additional online sites, I would like to keep up with anything fresh you have to post. Would you post a list of the complete urls of all your social pages like your Facebook page, twitter feed, or linkedin profile?

  • I seldom drop comments, however i did some searching and wound up here Using the Features of ASP.NET MVC 3 Futures - Imran Baloch's Blog.

    And I actually do have a couple of questions for you if it's allright. Could it be just me or does it seem like some of the comments look like they are coming from brain dead individuals? :-P And, if you are posting at other online sites, I'd like
    to keep up with everything new you have to post. Could you list of every one of all your
    social pages like your Facebook page, twitter feed, or linkedin profile?

  • Great goods from you, man. I have understand your stuff previous to
    and you are just too great. I really like what you've acquired here, really like what you are stating and the way in which you say it. You make it entertaining and you still care for to keep it smart. I can not wait to read far more from you. This is actually a terrific website.

Comments have been disabled for this content.