Tuesday, May 26, 2015

Custom HTML Helper for MVC Application

The solution to avoid this is to build a custom HTML helper to encapsulate everything and make the repetitive task less cumbersome.
Let's say we want to avoid doing this many times inside your views:
<img src="@myModel.MyObject.ImageSource", alt ="@myModel.MyObject.Imagename",
title ="@myModel.MyObject.ImageDescription" /> 
 
And instead, you want something Razor like that may take care of some logic or validations to avoid error because in the previous snippet, the ImageSource or Imagename or again the description may be null:
 @Html.Image(@myModel.MyObject.ImageSource, 
@myModel.MyObject.Imagename, @myModel.MyObject.ImageDescription) 
namespace MyNamespace 
 {  
    public static class MyHeleprs
    { 
        public static MvcHtmlString Image(this HtmlHelper htmlHelper, 
        	string source, string alternativeText)
        {
            //declare the html helper 
            var builder = new TagBuilder("image"); 
            //hook the properties and add any required logic
            builder.MergeAttribute("src", source);
            builder.MergeAttribute("alt", alternativeText);
            //create the helper with a self closing capability
            return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
        } 
    } 
}
To make this helper available in your view, add its namespace as follows:
@namespace MyNamespace 
But if you want it available in all your views, you have to add the namespace not to a specific view but to the collection of namespaces in views' web.config:
<add namespace="MyNamespace" /> 
 
Now, the Image helper is available everywhere in your views.

Custom DataAnnotations with client and server side both validation

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace System.ComponentModel.DataAnnotations
{
    public class SumitValidation : ValidationAttribute, IClientValidatable
    {

        public override bool IsValid(object value)
        {
            string strValue = value as string;
            if (!string.IsNullOrEmpty(strValue))
            {

                return strValue.ToLower()=="sumit";
            }
            return true;
        }

        public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            //yield return new ModelClientValidationRule() { ValidationType = "sumitvalidation", ErrorMessage = this.ErrorMessageString };

            var modelClientValidationRule = new ModelClientValidationRule
            {
                ValidationType = "sumitvalidation",
                ErrorMessage = FormatErrorMessage(metadata.DisplayName)
            };           
            yield return modelClientValidationRule;
        }
    }
}


using MVC5_Test.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;


namespace MVC5_Test.Controllers
{
    public class CustomAttributeController : Controller
    {
        //
        // GET: /CustomAttribute/
        //[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        [HttpGet]
        public ActionResult Index()
        {
           
            return View();
        }


        [HttpPost]
        public ActionResult Index(CustomValidation customValidation)
        {
          

            return View();
        }
    }
}



using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace MVC5_Test.Models
{
    public class CustomValidation
    {
        [Required]
        [SumitValidation]
        public string name { get; set; }
    }
}




@model MVC5_Test.Models.CustomValidation
@Scripts.Render("~/bundles/jquery")
@{
    ViewBag.Title = "Index";
}

Index




@using (Html.BeginForm())
{
    @Html.TextBoxFor(m=>m.name)
    @Html.ValidationMessageFor(m=>m.name)
    
  
}



 

Sunday, March 22, 2015

viewbag vs viewdata vs tempdata

1)TempData
Allows you to store data that will survive for a redirect. Internally it uses the Session as baking store, it's just that after the redirect is made the data is automatically evicted. The pattern is the following:
public ActionResult Foo()
{
    // store something into the tempdata that will be available during a single redirect
    TempData["foo"] = "bar";

    // you should always redirect if you store something into TempData to
    // a controller action that will consume this data
    return RedirectToAction("bar");
}

public ActionResult Bar()
{
    var foo = TempData["foo"];
    ...
}
2)ViewBag, ViewData
Allows you to store data in a controller action that will be used in the corresponding view. This assumes that the action returns a view and doesn't redirect. Lives only during the current request.
The pattern is the following:
public ActionResult Foo()
{
    ViewBag.Foo = "bar";
    return View();
}
and in the view:
@ViewBag.Foo
or with ViewData:
public ActionResult Foo()
{
    ViewData["Foo"] = "bar";
    return View();
}
and in the view:
@ViewData["Foo"]
ViewBag is just a dynamic wrapper around ViewData and exists only in ASP.NET MVC 3.
This being said, none of those two constructs should ever be used. You should use view models and strongly typed views. So the correct pattern is the following:
View model:
public class MyViewModel
{
    public string Foo { get; set; }
}
Action:
public Action Foo()
{
    var model = new MyViewModel { Foo = "bar" };
    return View(model);
}
Strongly typed view:
@model MyViewModel
@Model.Foo

After this brief introduction let's answer your question:
My requirement is I want to set a value in a controller one, that controller will redirect to ControllerTwo and Controller2 will render the View.
public class OneController: Controller
{
    public ActionResult Index()
    {
        TempData["foo"] = "bar";
        return RedirectToAction("index", "two");
    }
}

public class TwoController: Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            Foo = TempData["foo"] as string
        };
        return View(model);
    }
}
and the corresponding view (~/Views/Two/Index.cshtml):
@model MyViewModel
@Html.DisplayFor(x => x.Foo)

There are drawbacks of using TempData as well: if the user hits F5 on the target page the data will be lost.
Personally I don't use TempData neither. It's because internally it uses Session and I disable session in my applications. I prefer a more RESTful way to achieve this. Which is: in the first controller action that performs the redirect store the object in your data store and user the generated unique id when redirecting. Then on the target action use this id to fetch back the initially stored object:
public class OneController: Controller
{
    public ActionResult Index()
    {
        var id = Repository.SaveData("foo");
        return RedirectToAction("index", "two", new { id = id });
    }
}

public class TwoController: Controller
{
    public ActionResult Index(string id)
    {
        var model = new MyViewModel
        {
            Foo = Repository.GetData(id)
        };
        return View(model);
    }
}
The view stays the same.

ASP.NET Core

 Certainly! Here are 10 advanced .NET Core interview questions covering various topics: 1. **ASP.NET Core Middleware Pipeline**: Explain the...