ASP.NET MVC: Attributes and Semi Dynamic Check for Request Parameters

If I were self involved I would say something silly like IN THIS AWESOME POST but I’m not. However in this post that is awesome I gave some examples of how to use attributes to set defaults or just check to see if an incoming id could be matched to a record somewhere… Sorry lost my track of thought. Watching the begining of Transformers… You know the part where it could have been good.

Anyway, I figured I’d add another debatable use for an attribute, the CheckForGivenRequest one. Basically in the other post I had something that was specific it was checking for, this is used if you are checking for a request parameter but you don’t want to make an attribute for each and every one of them.

  //This is so you can use it many times on the same method
  //I know, I know... duh
  [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
  public sealed class CheckForGivenRequestAttribute : ActionFilterAttribute
  {
    //The constructor to set what should be looked for
    //Default amount is what it should be set if not there
    public CheckForGivenRequestAttribute(String requestParameterName, Object defaultAmount)
    {
      DefaultAmount = defaultAmount;
      RequestParameterName = requestParameterName;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      base.OnActionExecuting(filterContext);
      //Check the extra request parameters (ie &someId=1) for if it exists
      //If it doesn't exist, then add it
      if (!filterContext.ActionParameters.ContainsKey(RequestParameterName))
      {
        filterContext.ActionParameters.Add(RequestParameterName, null);
      }

      //If it's null set to the default
      filterContext.ActionParameters[RequestParameterName] =
         filterContext.ActionParameters[RequestParameterName] ?? DefaultAmount;
    }

    //Just the properties, nothing to see here.  Go away...
    private Object DefaultAmount { get; set; }
    private String RequestParameterName { get; set; }
  }

And then the use of it:

  [CheckForGivenRequestAttribute("someStupidId", 1)]
  public ActionResult INeedAnExample(Int32 someStupidId)
  {
    ...
  }

Now you might ask why not make that attiribute generic to avoid boxing.

Why not make that attribute generic to avoid boxing?

Glad you asked. Turns out that you can’t make attributes generic. Aparrently it’s somwhat debatable why but not possible at the time being. Besides, the ActionParameters collection is <String, Object> anyhow, so at some point any stuct would be boxed anyhow.

On a side note, I never noticed this before, but when one of the non descript Autobots crashes near a pool, some kid is there to ask if he is the Tooth Fairy? Seriously? Are kids really that dumb? Cause every picture I’ve seen of the Tooth Fairy has been a 20 foot tall metal thing with no discernible features.

ASP.Net MVC: Attributes, ActionFilterAttribute, and Why You Might Want To Use Them

So if you’ve used MVC, and I know you have because you want to be cool like me, you’ve most likely run into an error like this:

Certain parameter wasn’t found. Make [parameter] nullable.

In other words, the parameter didn’t show up in the URL and therefor MVC can’t assign a value to it. This would of course happen with anything that isn’t nullable. Now you could do this:

  void SomeAction(Int32? pageNumber)
  {
    if(someParameter.HasValue)
    {
      ..
    }
  }

But do you really feel like putting that in every stupid method that happens to have the same parameter? Say the parameter is something simple like pageNumber. Taking the above code, you would have to see if pageNumber has a value and if it doesn’t, continue to set some variable to a default. Kind of annoying to have to repeat that over and over again when you know you will be looking for pageNumber on many actions. Well Attributes, or more importantly ActionFilterAttribute, are the way to get around this.

Say with the pageNumber example you want a default of 1 if it doesn’t exist. Well that’s easy to do, it would be something like this:

    public sealed class CheckPageNumberAttribute : ActionFilterAttribute
    {
        private const String DefaultPageNumber = 0;

        //This will fire automatically on page load.
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            //ActionParameters.Values holds all the request parameters after the ? as in ?pageNumber=1
            //See if it exists first.  If not, add it
            if (!filterContext.ActionParameters.ContainsKey("pageNumber"))
            {
                filterContext.ActionParameters.Add(RequestConstants.PageNumber, null);
            }

            //Set to default if it's not null
            filterContext.ActionParameters["pageNumber"] = filterContext.ActionParameters["pageNumber"] ?? DefaultPageNumber;
        }
    }

So the method looks more like this now:

  [CheckPageNumberAttribute]
  void SomeAction(Int32 someParameter)
  {
    ...
  }

And you can now do your … without worry.

But what if the url is like this?

ShowMeACoolRoom/Index/1/

And you have your route set up like:

  {controller}/{action}/{roomId}

And you want to make sure that not only does that userId exist in the url, but the user actually exists. Well you don’t look to the ActionParameters.

  public sealed class RoomExistsAttribute : ActionFilterAttribute
  {
    public override void OnActionExecuting(ActionExecutingContext context)
    {
      base.OnActionExecuting(context);

      ChatRoom foundRoom = null;
      //RouteData.Values holds all the values in the url it was able to match to a route
      //Check the Values list in the RouteData for the id
      if(context.RouteData.Values.ContainsKey("id"))
      {
        //Convert to an integer, ConvertTo is just a method I've made.
        Int32? roomId =
          Convert.ToString(context.RouteData.Values["id"]).ConvertTo();
        if(roomId.HasValue)
        {
            foundRoom = ChatRoom.GetRoomByID(roomId.Value);
        }
     }

     //If the room isn't found, handle the error.
     if (foundRoom == null)
     {
       //redirect on error...
       context.Result =
         new RedirectToRouteResult
         (
           GeneralConstants.RouteName,
           new RouteValueDictionary
           {
              { "controller", "sharedError" },
              {  "action", "error" },
              { "name", "someErrorKey" }
            }
          );
       }
    }
  }

Now the new method looks something like this:

  [RoomExistsAttribute]
  [CheckPageNumberAttribute]
  void SomeAction(Int32 roomId, Int32 someParameter)
  {
    ...
  }

And once again you are free to … without worry of the room not existing. Next post I plan on adding some more “advanced” attributes… hahaha advanced? This site? hahahaha sorry. But I will be adding a new post about certain attribute solutions I’ve found that work well.

ASP.Net MVC: Routes, Route Contraints, and My Love Hate Relationship

So something that has been somewhat of an uphill climb as of late is routing in MVC. I think part of it is the way it works and part of it is that I’ve approached MVC like a 10 year old with a new game; F- the instructions, I’m all up in this.

What goes out must come in…

The biggest misconception I had with routes is that the route definitions meant something when a page is loading. This is bad. Now before the nerd rage starts to build, I will qualify that statement. Route definitions mean nothing beyond a simple mapping of values. What? Well suppose I have two routes:

   routes.MapRoute
   (
     ...
      "{controller}/{action}/{roomId}/{name}",
     ...
   );

and

   routes.MapRoute
   (
     ...
     "{controller}/{action}/{userId}/{name}",
     ...
   );

Now on the way out, the system can find the route easy if you supply the correct route data: (Lets say for the second route)

  routeValues = new RouteDicationary()
  routeValues.Add("controller", "Room");
  routeValues.Add("action", "Index");
  routeValues.Add("userId", 1);
  routeValues.Add("name", "ProgramminTool");

  neededHelper.RouteUrl("SecondRoute", routeValues);

Which will give me a wonderful address of:

  /User/Index/1/ProgramminTool

Awesome, the routing system did what I wanted. Problem is, I assumed too much coming in, ie when the page is loading from the url. (Say from a clicked link) I kept getting an error like:

RoomId doesn’t exist. Make roomId nullable. Blah blah blah I hate you and you should quit programming and do something more equal to your ability level like spinning in circles.

Though I might have take some artist license on the error, the meaning was simple: it was trying to run that url against the Room controller and it couldn’t find the roomId parameter in the request. Well that doesn’t make sense, after all it’s obvious that it should be looking for the user controller and use the route with the userId paramter. Sadly, it doesn’t work that way and not sure it could. Why? Well look at the url.

/User/Index/1/ProgramminTool

Now if you were too look at that, what would you think? You have four values, values that you can’t really guess the type since you have no real context. After all there could easily be a method that takes in a string userId as opposed to an integer userId. On top of that, it has no idea what the 1 is. There’s no userId=1 to tell it what it is. So what does it do? It goes down the route table and finds the best fit. Now you tell me, which does this url fit better?

  "{controller}/{action}/{roomId}/{name}"

Or

  "{controller}/{action}/{userId}/{name}"

It’s kind of a trick question since the answer is neither. It will just fit it to the first one that it likes, and in this example it’s the roomId one. Problem is, now the user controller method that is looking for the userId fails because there is no userId. Uhg.

Computers are dumb, they can only do what we tell them.

Fact is, in this situation I have to make some rules for the routing system to take in and start digesting the url properly, and there’s a way to do this: IRouteConstraint.

Say that you have certain controllers or actions you don’t want to use the first route. For this example I’ll use user actions from my current project. On the room index view there is a button for adding the room as a favorite. Now the action/method it needs is on the user controller, not the room controller. Therefore I have to post some information to the user controller using a route that looks like this:

  "{controller}/{action}/{userId}/{roomId}"

But it is preceded by one that looks like:

  "{controller}/{action}/{id}/{name}"

See the issue? Now when MVC generates the url, everything is fine. After all it uses the route name and the parameters to pick the correct route. On the way in, not so good. It naturally tries to conform the url to the id/name route. BOOM HEADSHOT! Now the solution.

public class NotGivenAction : IRouteConstraint
{
  //This is the action that we want to prevent from the route accepting
  private String GivenAction { get; set; }

  public NotGivenAction(String givenAction)
  {
    GivenAction = givenAction;
  }

  public Boolean Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection)
  {
    String parameterValue = values[parameterName].ToString();
    //Make sure the parameter exists and it doesn't match the bad action
    return values.ContainsKey(parameterName) && parameterValue != GivenAction;
  }
}

The IRouteConstraint interface has a method Match that has to be given life. The short of it is take in the parameter name and find it’s value and then see if the value is the same as the action it’s looking for. For example, if I had an action of AddToFavorites, this would go through and make sure it isn’t that action. If it is, it knows to not use the current route for this action.

routes.MapRoute
(
  GeneralConstants.RouteIdName,
  "{controller}/{action}/{id}/{name}",
  new { controller = "Room", action = "Index", id = "0", name = "None" },
  new { action = new NotGivenAction(UserControllerConstants.AddToUserFavorite) }
);

routes.MapRoute
(
  GeneralConstants.RouteUserIdRoomId,
  "{controller}/{action}/{userId}/{roomId}",
  new { controller = GeneralConstants.ControllerUser, action =   UserControllerConstants.AddToFavorites, userId = "-1", roomId = "-1" }
);

So now it will skip the first and push to the second when the url looks like:

  /User/routes.MapRoute/AddToFavorites/1/2/

Take that you f-ing routes. KING KONG AIN’T GOT S- ON ME!

ASP.Net MVC: Is the Use of jQuery/Asynchronous calls a Must?

In this wonderpost, I questioned the use of jQuery in the mind of the purist MVCist. (If that’s not a word yet, it is now and I expect royalties.) Now I’ll flip it tool style and ask it from another direction: Can MVC survive without jQuery?

Here’s the situation: I have a site that I made a while back (Basically a phone friendly chat room emulator) that was kind of experiment on a couple levels, one being the use of Entity Framework and WebForms. (It’s here if you are curious… right now you have to make an account though. Never got around to allowing non logged in users.) Another part was to see if I could make a multi phone compliant page that had to be fast and work on as many phones as possible. (Anything with a browser at least) And had to be touch friendly. (No links, just buttons)

A week back I decided, after trying to make new sites with MVC, to take an existing work and really give MVC a rugged test. Eythere was just that site. Now personally I thought this would be pretty simple since MVC seemed really good at simple, non business sites. What could be more simple than a chat room emulating site that has no javascript? (Aside from whatever Javascript WebForms use for postbacks) I mean in the end, it’s just a bunch of buttons right?

Yeah turns out what those buttons did was at the heart of my issues. You see, with WebForms, everything done on a page is meant for that page. Sure you can defer how things are handled from the page to another tier, but the action itself belongs to the page. For example, say that a user wanted to make a room a favorite, well there’s a button named favorite that he/she clicks to do so.

 Oh the lovely colors.

In webforms, the Room.aspx page would handle the Favorite button click and the current user’s favorite list would have the room removed or added depending. But the call to the add/remove would be handled by the button’s click event and then the page would be reloaded. Something we in the know call “easy”. (Like that word? Use it. It’s free because I’m such a nice guy)

Now with MVC it’s a whole new ballpark. With controllers, it becomes of question of what controller should handle this. It could go onto the room controller, but in the end it deals with a user and adding something to the user. So it’s fair to say that this is probably a job for Superman if Superman happens to be a UserController or you’ll most likely end up repeating code.

Now the issue: How is this handled? Whether link or button, something has to be posted to the user controller. Posting to the controller means that the controller, on finish, has to create a model and send it to a view. Well this kind of sucks doesn’t it? The user clicks the + Favorite button and bam is taken to a whole new page.

SURPRISE IT’S BEEN ADDED TO YOUR FAVORITES!

Not what I would call fluid. The other thought it to have a redirect, which in the end is more fluid in that it takes the user back to the original page BUT with that you have to send a lot of information back and forth. After all, in MVC a lot of the information for a given “page” is passed using get. So for instance you have a room with a roomid and a page number and a count of items to show and possibly a sort you’re looking at:

/Room/1/?pageNumber=1&amountToShow=5&sort=Date

Which means all of that has to be sent to the User controller in order to save the state, has to be put in session/some kind of user cache, or you just send the entire url. In any case, something has to be tossed around for this to work. More seamless than the other way but it is a lot of work for something so simple.

When it comes to ease of UI design, jQuery/asynchronous operations are a must.

Something I think that the MVC idea fails at it in a UI sense it was makes it strong in a programming sense, logical separation of tasks. Right off the bat, I hated the way WebForms handled AJAX “web methods”. Having to repeat methods per page so they could be “registered” was ugly and a pain. MVC and it’s separation/REST ways makes asynchronous calls so easy. However, what used to be a simple operation in WebForms has now become cumbersome without outside help. Straight up, it seems impossible to do non drill down design without using jQuery or some kind of javascript library equivalent without killing the separation that MVC seems to embrace.

Why is this a problem? For the most part it isn’t. Most people aren’t going to try something like EyThere (Wouldn’t recommend it, it was a pain) since how many people create sites with multiple phones in mind? However, it does serve to show what seems to be a glaring annoyance with MVC. Either use asynchronous calls or just sink.

ASP.Net MVC Issue: Form With Get Method Not Passing Request Values

DISCLAIMER: This has a solution but there has to be a better way.

So I came across a really odd situation with the MVC framework today, and I’m on the edge of some serious Nerd Rage. Here’s the issue:

I have a route that looks like this:

  "{controller}/{action}/{roomId}/{name}"

And a form that looks like this:

  <form action="Room/Index/6/SomeThing?pageNumber=1&amountToShow=5" method="get">
   <button type="submit">SomeButton</button>
  </form>

Can’t get much simpler… or is it more simple? Whatever. Point is, when the the button is clicked, it should go to that page like the form action says to. And it does, sort of. For some reason it ends up stripping the values from the pageNumber and amoutToShow request variables. How do I know this? Well break points at certain times show me that the current ActionExecutingContext ActionParameters (the thing that stores all the request parameters) has the two I need but neither has a value. And since they are not included in that route description, it must see them in the url.

You might think it has to do with forms and submitting, and it might except here’s the kicker… with a route like this:

   "{controller}/{action}/{roomId}/{name}/{pageNumber}/{amountToShow}"

All of a sudden it can see the values. Mind you the url ends up like:

  Room/Index/1/Something/1/5

Which you would expect from the route definition. To add to the fun, if I add hidden values:

  <form action="Room/Index/6/SomeThing?pageNumber=1&amountToShow=5" method="get">
    <input type="hidden" name="pageNumber" value="1" />
    <input type="hidden" name="amountToShow" value="5" />
    <button type="submit">SomeButton</button>
  </form>

It works with the original route. Doesn’t really make sense to me, but my understanding of the system isn’t exactly expert level. However, I could buy this if the hidden field method worked and the extended route definition didn’t.

For now I can use the hidden input method since there’s no issue with showing the parameters. Just not what I’d call “Best solution” types stuff.

Sigh. MVC : One step forward, two steps back.

Are jQuery and Asynchronous Calls against MVC?

This is something I started to think about the other day as I have been diving deeper into MVC. In it’s purest form, at least to what I understand, is that the whole idea of MVC is to have a separation between information handling (controller), information delivery method (model), and the information presentation (View). What this means is that the View itself should only be around to display or return information, but that’s it. Have a form? Great, here’s the information you need to fill out and I’ll send it on it’s way. And even with that idea, the View itself doesn’t really send anything. It just passes what it knows off to the model and it’s back in happy land. (The view gets nervous sometimes… performance anxiety) The whole system works well in actuallity, it does what is expected. There are no events simulated and possibly tangled. There’s no smoke and mirrors when it comes to the display and what the user is seeing. I want a grid of users? Here it is. I want to edit this user? Great! I’ll take you to the page that does that. Life is great and wonderful.

But wait, here comes jQuery, Json, and Asynchronous Calls. Now I can do crazy things with the view that I could never do before. Remember that grid of users? Well you don’t really have to go to another page to edit. Hell, just click this link and a form can appear to take in what you need to change. Even better, the grid itself will change and allow you to edit any row you want, and when you’re done the grid will come back all new an refreshed. What a crazy party this is now. Kind of sounds familiar right? Yeah WebForms. With these three helpers we’ve now cut out the middle man in the Model and passed the savings onto you. Essentially the whole idea has been chucked and jQuery has allowed us to invoke the same event model WebForms was chastised for. In fact, you could go to the logical end and have one page once again that controls everything. The View once again has the power much like it did in WebForms (provided you look at the Page and code behind being more like a View than separate entities). Isn’t that the whole thing we were trying to get away from?

I suppose you could make the argument that no one is putting a gun to your head to use jQuery for anything other that simple things like UI manipulation (date pickers, sliding controls, drag drop, ect) but that wouldn’t be the situation being argued here, now would it?

ASP.Net MVC: Create a link method… ie JUST GIVE ME THE STUPID URL

One thing that kind of annoys me is the situation where you just want a url, but you don’t want one of the prepackaged links using:

   Html.RouteLink
Or
   Html.ActionLink

Mostly because you want to be able to create your own html and you only want the created url. Well turns out there’s a method for this: The RouteUrl method on the UrlHelper class. Down side is that it’s not static and takes a few lines to use, so not cool UI design side. Well here’s a method that uses that method and gives you a method to exact a method of victory. I think that sentence had promise, but fell short of complete failure.

Anyways, here it is… The “Just give me the stupid url” method, CreateUrl for short.

        public static String CreateUrl
        (
          RequestContext context,
          RouteCollection routeCollection,
          String routeName,
          String controller,
          String action,
          RouteValueDictionary routeValues
        )
        {
            //Create the helper
            UrlHelper neededHelper = new UrlHelper(context, routeCollection);

            //get the route to check what it is holding at far
            //as defaults go
            var neededRoute = (Route)routeCollection[routeName];

            //this might be overkill honestly.  Basically in case the
            //Route contains the "controller" key only then add it to the
            //values for the route.  Otherwise just ignore.  It's possible
            //someone might pass in a controller/action but the route
            //doesn't take them. At which point you'll
            //be showing the "Aw maaaaan" face.

            if (!String.IsNullOrEmpty(controller) && neededRoute.Defaults.ContainsKey("controller"))
            {
                routeValues.Add("controller", controller);
            }

            if (!String.IsNullOrEmpty(action) && neededRoute.Defaults.ContainsKey("action"))
            {
                routeValues.Add("action", action);
            }

            //And then the call to create the url string.
            return neededHelper.RouteUrl(routeName, routeValues);
        }

And in use View side:

  <a href="
  <%
  CreateUrl
  (
    Html.ViewContext.RequestContext,
    Html.RouteCollection,
    GeneralConstants.RouteDefault,
    "SomeController",
    "SomeAction",
    new RouteValueDictionary { { "id", 1 } }
  )
  %>"
  >
  Something is linked
  </a>

Now mind you I did use a link there so it seems like a silly example. However, you can do many other things now that you just have the url itself.

Asp.net Mvc Master Page: System.Data.Entity Must Be Referenced

Ok maybe you’re better at figuring out the obvious than I am, but this was annoying me. On my master page I happened to be using an object from another assembly that used the Entity Framework. Now by habit, I have this assembly:

System.Data.Entity, Version=3.5.0.0

Referenced to the UI project, so it was a little of a surpise to me that I was getting this error on the master page. (And the views, but I don’t use anything in Views not supplied by Models) I was at a loss as to how to get the thing to work.

Now I could use this:

<%@ Assembly Name=”System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089%>

On the page, but would be silly to do that all the thing, and DUH in WebForms… or ASP.Net Classic, is to put it in the stupid web config.

  <system.web>
    ...
    <assemblies>
      ...
      <add assembly="System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
      ...
    </assemblies>
  ...

No more problems.