MVC cannot have two actions with the same name

You can compile any controller to have the same method name if they have different parameter type or numbers. This is normal in .Net framework but what MVC developer must know is that you cannot have 2 actions (which are methods) with the same name even if they doesn’t have the same parameter type. That mean you cannot have :

public ActionResult Edit(int id)
{
   //...
}

and in the same controller having:

public ActionResult Edit(MyObjectToEdit obj)
{
   //...
}

This will fail when you will call these because the MVC framework won’t know which one to call. You have two solutions to make MVC routing know which action to use. First, you can change the name. I think it’s obvious that if you have different name that the routing won’t have any problem to know which one to choose.

The second solution is to add the attribute POST, GET, PUT, DELETE. This will tell depending of the header. So you could have:

[HttpGet]
public ActionResult Edit(int id)
{
   //...
}

[HttpPost]
public ActionResult Edit(MyObjectToEdit obj)
{
   //...
}

From here, you could call them by specifying in the Http Request the type of request you sent (Get or Post) and the MVC’s routing system will know which one to choose.

Wait a minute

Alright, there’s a catch and it’s if you return from those methods Json cause you cannot return Json from a Get request by default. This is for security purpose. In fact, someone could do the attack Json HiJacking and harm you only if:

  • You return data into an array. This can be solved by returning into an object that may contain array.
  • Return sensitive information. This can be solved by using SSL.
  • Using Get with Json. This can be solved by using Post or having multiple name instead of having the same action with two types of Http call type.
  • The browser support “__defineSetter__” which is where the vulnerability is executed. this one, you have no control.

So, it’s not a big deal if you know what you are doing. In most case, you can allow Json to return data from Get if you handle what your action return. This mean, you should know what object you return and not returning an array directly.

To allow Json to use Get to return data, simply add as a second parameter JsonRequestBehavior.AllowGet. This will remove all possible errors.

return Json(new  { MyData = 1, MyData2= "ASD" }, JsonRequestBehavior.AllowGet);

How to step in (debug) Asp.Net MVC source code?

If you need to go inside ASP MVC code which can be very instructive you just need to hit 3 checkboxes inside Visual Studio and you will be ready to go.

First of all, you need to go on the Debug>Options and Settings. This will open the Options of Visual Studio. From the Debug menu, you should already be in the good menu which is Debugging.

Select the first sub-menu which is called “General” and uncheck “Enable Just my code (managed only)”. Check “Enable .Net Framework source stepping” and check “Enable source server support”. That’s it. You will be able to step into the .Net source code and also set breakpoint inside the Microsoft code.

Using the System.Web.Cache object into your MVC3 project

Sometime you may need to store information for few times in the memory without having to compute the data every time a user request it. This can save time and also processor time. To do, we can use the System.Web.Cache object.

var cc = HttpRuntime.Cache.Get("Test");
DateTime t;
if (cc == null)
{
   t = DateTime.Now;
   HttpRuntime.Cache.Insert("Test", t);
}
else
{
   t = (DateTime)cc;
}

The code above set into the cache the value of the current time and for all subsequent calls will get the value from the cache instead of getting the date itself. This demonstrate that in fact, it won’t do exhaustive calculation (date in this example).

HttpRuntime.Cache.Get let you get an object from a key. The key is set when you are using HttpRuntime.Cache.Insert.

The Insert method has many parameters. The first parameter is the key, the second the value. Other parameters are concerning the time the value will stay in cache. The third parameter is by default NULL but could be anything that if changed will flush the cache. The forth parameter is the time when the data must be removed form the cache in an absolute time. For example, you can wrote that you want the data to be removed 20 minutes later by setting the DateTime.Now + 20 minutes ( DateTime.UtcNow.AddMinutes(20) ).

The last possible parameter is the sliding which decide if it gives additional time to the expiration of the cache if the data is accessed. This parameter is a TimeSpan. If you say 1 minute in this parameter you will have the data stored for 1 minute after the last get is done. This give you 1 minute time frame every time a user Get the value from the time you Inserted it. If at anytime no body access the cache, even the first 1 minute, the cache is resetted for this key. You can say that you do not want to use absolute time by setting this one to Cache.NoAbsoluteExpiration and only set a TimeSpan.

HttpRuntime.Cache.Insert("Test", t,null, Cache.NoAbsoluteExpiration, new TimeSpan(0,0,1,0));

or to set it for 20 minutes

HttpRuntime.Cache.Insert("Test", t, null, DateTime.UtcNow.AddMinutes(20), Cache.NoSlidingExpiration);

If you try to use the absolute and sliding in the same time you will get the an Argument Exception.

This mean you can only use one of the type in the same time. It’s also possible to have a call back when the data is removed from the cache. This can be interesting if you need to act differently when something is access removed from the cache. To do, you need to set the CacheItemRemovedCallback. This method will be called whenever the cache is removed. If you set 1 minute, 1 minute after the call back will be raised. This is raised what ever happen on the server side, even if no client call the server.

HttpRuntime.Cache.Insert("Test", t, null, DateTime.UtcNow.AddMinutes(1), Cache.NoSlidingExpiration, CacheItemPriority.Normal, onRemoveCallback);

This method will give you also the detail about why it has been removed. Your item might have been set to stay 30 minutes but because low memory is running that the cache system will removed it. You will get the reason with the enumerator CacheItemRemovedReason.

It’s pretty much it about the Cache for basic use. Do not forget that the data is cached into the memory of the process and is not shared across multiple server if you have multiple Web Server. You should use server with affinity to be able to reuse the cache for a same client otherwise the cache will be good only for the Web Server who has inserted the values.

Returning a JsonResult within the Error function of JQuery Ajax

Let say that you have an exception on the server side and you want to specify this error to the client, what could you do?

The easiest way is to return the error into the return value directly:

public JsonResult Create(MyObject myObject) 
{
	//AllFine
	return Json(new { IsCreated = True, Content = ViewGenerator(myObject));
	
	//Error
	return Json(new { IsCreated = false, Content = ViewGenerator(myObject), ErrorMessage = 'Could not save because XYZ');
}

In the Javascript, we just need to take the error message and display it.

$.ajax({
     type: "POST",
     dataType: "json",
     url: "MyObjectController/Create",
     data: JSON.stringify(myObjectJson),
     success: function (result) {
       if(result.IsCreated)
	   {
		//...
	   }
	   else
	   {
		alert(result.ErrorMessage);
	   }
      }
  });

This is a correct way to do it. But sometime, you may want to return handled error this way because you “control” the situation and do something else for unhandled error. This could be the case of any error that you do not catch with precision but you still need to return something to the client. Since you are using Ajax you may not want to redirect your user to another page but just to display an alert that the operation is unsuccessful.

This can be done by changing the Response Header with a Http Code that is different from the normal 200.

public JsonResult Create(MyObject myObject) 
{
	//AllFine
	return Json(new { IsCreated = True, Content = ViewGenerator(myObject));

	//Use input may be wrong but nothing crashed
	return Json(new { IsCreated = False, Content = ViewGenerator(myObject));	
	
	//Error
	Response.StatusCode = (int)HttpStatusCode.InternalServerError;
	return Json(new { IsCreated = false, Content = ViewGenerator(myObject), ErrorMessage = 'Could not save because XYZ');
}

The Javascript can than go in three different direction:

$.ajax({
     type: "POST",
     dataType: "json",
     url: "MyObjectController/Create",
     data: JSON.stringify(myObjectJson),
     success: function (result) {
       if(result.IsCreated)
	   {
		//... ALL FINE
	   }
	   else
	   {
		//... Use input may be wrong but nothing crashed
	   }
	 },
    error: function (jqXHR, textStatus, errorThrown) {
            alert("Error:" + jQuery.parseJSON(jqXHR.responseText).Info); //Error

        }
   
  });

This way, you handle in a clear way how to display error to the user or to display problem with his inputs. It also give you the possibility to do it in a clean way at the server side and also to the client side.

For you curiosity, if you want to play with different status you can go see in System.Net the enumeration HttpStatusCode all different possible values.

Here is it:

namespace System.Net
{
  public enum HttpStatusCode
  {
    Continue = 100,
    SwitchingProtocols = 101,
    OK = 200,
    Created = 201,
    Accepted = 202,
    NonAuthoritativeInformation = 203,
    NoContent = 204,
    ResetContent = 205,
    PartialContent = 206,
    Ambiguous = 300,
    MultipleChoices = 300,
    Moved = 301,
    MovedPermanently = 301,
    Found = 302,
    Redirect = 302,
    RedirectMethod = 303,
    SeeOther = 303,
    NotModified = 304,
    UseProxy = 305,
    Unused = 306,
    RedirectKeepVerb = 307,
    TemporaryRedirect = 307,
    BadRequest = 400,
    Unauthorized = 401,
    PaymentRequired = 402,
    Forbidden = 403,
    NotFound = 404,
    MethodNotAllowed = 405,
    NotAcceptable = 406,
    ProxyAuthenticationRequired = 407,
    RequestTimeout = 408,
    Conflict = 409,
    Gone = 410,
    LengthRequired = 411,
    PreconditionFailed = 412,
    RequestEntityTooLarge = 413,
    RequestUriTooLong = 414,
    UnsupportedMediaType = 415,
    RequestedRangeNotSatisfiable = 416,
    ExpectationFailed = 417,
    InternalServerError = 500,
    NotImplemented = 501,
    BadGateway = 502,
    ServiceUnavailable = 503,
    GatewayTimeout = 504,
    HttpVersionNotSupported = 505,
  }
}

How to unit test a method that return an anonymous type?

It’s really easy to have in ASP.NET MVC a function that return an anonymous type. I say in ASP.NET MVC but this could be also in ASP.NET. In fact, when you have an action inside a controller that return a JsonResult you can simply return an anonymous type and Javascript will be able to handle it as simple as using the same syntax that you would use with object in C#.

public JsonResult Update(MyObject o)
{
 //...
 return Json(new { IsSaved = false, Id = 123});
}

In Javascript you would use :

//...Ajax call
 success: function (data) {
   var x = data.IsSaved;
   var xx = data.Id;
}

To unit test this scenario, you need to do two things. First, you need to use the dynamic keyword of .Net to be able to receive from the controller the response of the action which is anonymous.

dynamic returnedData = myController.Update(new MyObject());

The problem is that everything that has been generated as anonymous in a DLL stay internal. If you are doing you unit testing in a separated assembly (DLL) you will need to explicitly say that you want to share internal values with another assembly. This can be done by modifying the assembly configuration by editing AssemblyInfo.cs. You need to open the file AssemblyInfo.cs of the tested controller and add the following statement.

[assembly: InternalsVisibleTo("Tests.Unit")] 

This will give the permission to see internal to the unit testing project called “Tests.Unit”.