Programming By A Tool Freshly squeezed C# now with more pulp!



16Dec/090

Data Annotations, MVC, and Why You Might Like Them

So if you were like me before I knew what Data Annotations were, you most likely would be thinking, "What are Data Annotations?". Well I'm glad I can read your mind and therefore I am glad you asked.

Now the fun part about this post is that I might have to admit I was wrong. Why would that be? Well in this post I suggested that validation rules would be set in the controller. Turns out, there is possibly a better place, on the model itself. How can this be done??? Well that's what you're about to find out.

Say you have a user create model:

  public class AddUserModel
  {
    public String UserName { get; set; }
    public String Password { get; set; }
    public String RepeatPassword { get; set; }
  }

Now you could have a method on the controller like:

  public ActionResult AddUser(AddUserModel model)
  {
    if(IsValid(model))
    {
      ...
    }
  }

Where you have to create the IsValid method for every model on the controller that you need to validate (And possibly on other controllers if you are sharing models between them...) Or you can have this:

  public ActionResult AddUser(AddUserModel model)
  {
    if(ModelState.IsValid)
    {
      ...
    }
  }

And that is already built in so no validation method needed. But how is that possible? Attributes on the model or namely the ValidationAttribute class.

First off you have to include the System.ComponentModel dll in the project. Simple enough. Please say you know how to do that or do me a favor and remind yourself to blink. OK done? Good.

Now you can use some of the built in attributes which is good. Things like required are nice:

  public class AddUserModel
  {
    [Required]
    public String UserName { get; set; }
    ...
  }

There you go. Now if the UserName is null or empty, the ModelState will no longer be valid and will fail this check:

  ModelState.IsValid

Now you might wonder what the error message will be for that? Honest answer: I have no f--king clue. That's why you can actually set it. Those guys at Microsoft thought of everything.

  public class AddUserModel
  {
    [Required(ErrorMessage = "ENTER A USERNAME IDIOT!"]
    public String UserName { get; set; }
    ...
  }

The guys in the legal department have told me I have to note that your error message should change depending on your use and you shouldn't use the one above. Whatever.

Now you might want to actually pass the errors back, and why wouldn't you? You're a fine, upstanding, and thoughtful person and I lie like a crook. The errors, if there are any, are in here:

  ViewData.ModelState.Values

And you can use two loops to get to all of them, but I think the parent loop will only run once.

  foreach (ModelState state in ViewData.ModelState.Values)
  {
    foreach (ModelError error in state.Errors)
    {
      messageList.Add(error.ErrorMessage);
    }
  }

Pretty nice huh? Maybe if you're an idiot who just learned about this. For cool people like me, it's old news.

What's the point this? If "this" is data annotations: Well it helps move some of the validation off the controller if you are looking for a more "Fat model, skinny controller" design which I'm told is a good idea. This also gets rid of all the validation methods and saves time because of it.

If "this" is your life? I have no idea. But if you're to the point that you're asking me about the meaning of your life, you are in some serious trouble.

Bookmark and Share
26Oct/090

ASP.Net MVC: Quick Overview of Controller Structure

Wow, that's a mouthful far as titles go, but couldn't think of a better way to say it. Now what I'm about to go through is the "system" I have found that works pretty well when it comes to structuring controllers knowing that there will be asynchronous operations. Why is that a big deal? Well where you put certain methods can depend on which controller actually owns the action.

When I started using MVC, I had some issues on figuring out how to build controllers so that they made sense from a structural point of view. I slightly touched on it but I wanted to show where I progressed to in the vain hope that I can help prevent stumbling on your part.

One thing to be noted is the asynchronous part. I've become a firm believer that MVC is pointless without asynchronous operations. Why? Simply put, you can use them or you can come up with some annoying post and redirect for any create, update, or delete operations. If you're going to do that, you might as well just be institutionalized because you are one masochistic mother f---er. For everyone else in the happy world, go with something like jQuery that makes it real easy to perform said operations.

With the last paragraph in mind, the part I had trouble with the most was figuring out where the actions go. You see, when I started using MVC, I grouped stuff in an ultra simple manor. Say I have a site for handling pictures. Well there would be a view controller that would have anything to do with viewing images and an admin controller that took care of the uploading, changing, deleting, ecting. As you can imagine, this was not what you might call ideal.

Once I got a feeling for MVC and how it worked, I started having things a little more separated but still didn't feel right. I had actions for viewing a list of images on the image controller no matter if public or admin side which wasn't really ideal to me since it kind of blurred what was public and what was restricted from a conceptual point of view.

It wasn't until I started thinking in terms of unit testing that it started to make more sense. If I were creating controllers as if they were classes instead of pages like with WebForms, maybe it would work out better. Seems real profound right? Well it was at the time since I still had WebForms state of mind. All of a sudden, it made way more sense on how the controllers should be set up. In an odd way, the controllers almost became almost business layer like. If I wanted to update an Image, there would be an Update method on the image controller responsible for taking in the changes, validating, and dealing with the entity objects. Everything that had to do strictly with displaying information would be handled by a display controller like the before mentioned Admin controller. So something like:

Controller Outline

As you can see, the Admin controller has something to show all users. The User controller has the methods for things like updating, creating, and validation. Basically anything that would change an image is on one controller. Anything for showing it on the main section controller. That is, a controller that embodies an overall concept like say an Admin section of a site or possibly a controller for viewing galleries.

The sequence of events (bad word choice...) would be something like:

Open Admin/UserList/
Admin controller uses User Entity to retrieve list
Admin View shows User List
User clicks delete button/link on Admin View
Javascript/jQuery method invoked to send id to User/Delete
User controller receives id
User controller validates id to make sure it is valid
User controller validates current user to see if allowed to delete
User entity Delete method invoked by User Controller
Result of Delete Method is returned by User Controller (JSon preferably)
Admin View displays the result

Treating controllers like classes (and the use of anonymous actions) allows a very clean separation of actions resulting in a nice logical layout. Beyond this, it also allows for a greater separation between controllers which means its possible to do multiple parts of the entire project in parallel.

Maybe this is just stating the obvious, something I'm pretty good at, but my hope was to give a quick over view of laying out controllers for those who are just starting out.

Bookmark and Share
Tagged as: , No Comments
16Oct/090

ASP.Net MVC: Attibute to Check if Route Value Exists and… and Means Something!

Get ready for a roller coaster ride around the insanity that is me. You might actually find it amusing but most likely you'll just leave sick or underwhelmed. Don't feel bad if you do, you wouldn't be the first and, thanks to somehow being impervious to Natural Selection, you won't be the last. Be proud.

Here's what this post is about: Say you have a url like eh:

/User/View/1

Where 1 represents a UserId to a user that exists in some matter of context. (Does that makes sense?) Well there are a couple of things that could go wrong here. For one, if you don't want to have a nullable id in your signature:

  public ActionResult View(Int32? userId)

This could cause ouch:

/User/View/

But this problem is deeper. Much deeper. In fact so deep it deeper than even Piper Perabo has ever deeped before. Yrraaaahh!

What if the id doesn't even refer to anything? Say the id is 101 but there's no user with the id of 101? Beyond that, what if the id could be Id in some routes but UserId in others? WHAT WOULD YOU DO???

The idea here is to have something neato like this:

  [UserExistsById]
  public ActionResult View(Int32 userId)

And if that id is junk, then you redirect to an error page. Well if this sounds interesting, I'd be surprised, but read on in the event that it does.

Now this isn't accomplished in the most simple manor, but for good reason: The more time in means the less time repeating. First method we need is something to simply check the route data to see if something exists:

  public static Boolean RouteDataValueExists(ActionExecutingContext filterContext, String idToCheck)
  {
    return filterContext.RouteData.Values.ContainsKey(idToCheck);
  }

Real easy. It either has been digested by MVC and regurgitated into some kind of route value or it hasn't. Basically this is the first check. After all, if it doesn't exist why bother going further?

Next is the method that will be calling this one. Mainly one that uses the RouteDataValueExists and if returns true, then it actually checks the value against where ever the user is persisted.

  public static Boolean ValueFoundAndItemExists
  (
    ActionExecutingContext filterContext,
    Enum idToUse,
    Func<ActionExecutingContext, Enum, Func<Int32, Boolean>, Boolean> check,
    Func<Int32, Boolean> exists
  )
  {
    Boolean checksOut = false;
    String convertedId = idToUse.ToString();

    if (RouteDataValueExists(filterContext, convertedId))
    {
      checksOut = check(filterContext, idToUse, exists);
    }

    return checksOut;
  }

Ok so kind of a lot at first and it's hard to decide how to present this system, so just go with it.

  Enum idToUse,

This is a design choice. In reality this will be turned into a string anyhow, but the idea is it will be what to check the route values for. So if you are checking for UserId, you will pass in UserRequestTypes.UserId. Again this was a choice on my part as I hate passing text around.

  Func<ActionExecutingContext, Enum, Func<Int32, Boolean>, Boolean> check,

This is the method that will be used by ValueFoundAndItemExists to delegate out the actual checking if the id is an integer and is a real user.

Func<Int32, Boolean> exists

This will be the method that you will use to delegate the whole checking if it exists in the database. Something like:

  class User
  {
    public Exists(Int32 id)
    {
       return EntityContext.Context.User.Any(user => user.Id == id);
    }
  }

Still with me? No? Greeeeat. Next up is the base class that contains the

  Func<ActionExecutingContext, Enum, Func<Int32, Boolean>, Boolean> check,

parameter from above.

public abstract class BaseExistsAttribute : ActionFilterAttribute
{
  protected Boolean Exists
  (
    ActionExecutingContext filterContext,
    Enum idToUse,
    Func<Int32, Boolean> exists
  )
  {
    Int32? id = Convert.ToString(filterContext.RouteData.Values[idToUse.ToString()]).ConvertTo<Int32>();
    return id.HasValue && exists(id.Value);
  }
}

Ok so something might look familiar like well basically all the parameters. The reason for this is that there is a little bit of delegate passing going on with this whole system. One method passes on methods to other method in some kind of crazy method hoe down without the flanel shirts.

You will notice the use of the enum in this part:

  idToUse.ToString()

Again, you can easily just pass in a string instead of an enum, I just did this to stay away from strings.

Only thing that might be of interest is the ToConvert method that you can find here. You don't have to use it, you can simply just do a try parse on the

  filterContext.RouteData.Values[idToUse.ToString()])

To get an integer. That's up to you. I could have just put that in the code for you to see but then I couldn't randomly plug another post of mine.

Finally you have the actual attribute class:

  [AttributeUsage(AttributeTargets.Method)]
  public class QuoteExistsByQuoteId : BaseExistsAttribute
  {
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      base.OnActionExecuting(filterContext);

      if
      (
        !MvcMethods.ValueFoundAndItemExists
        (
          filterContext,
          UserRequestTypes.UserId,
          Exists,
          UserEntity.Exists
        )
      )
      {
        filterContext.Result = SiteMethods.ErrorOut(ErrorNames.General_PageError);
      }
    }
  }

And now it all comes together.

  UserRequestTypes.UserId

This is the enum I've been talking about this entire post! Now that I think of it, not really exciting.

  Exists

That's the method on the base class that checks for everything.

  UserEntity.Exists

And that's the method I need to check the persistence if the user is real. Remember? Takes in an integer and returns a boolean? Yes? Yes? No?

What's ErrorOut? Again this is just a method I made to create an ActionResult that is an redirect to an error page. Not hugely important. It's just what handles the situation when the value is bogus.... dude.

  [UserExistsById]
  public ActionResult View(Int32 userId)

And there you have it. Hopefully it was useful in some way but I'm not of touch with reality.

Bookmark and Share
Tagged as: , No Comments
14Aug/090

ASP.Net MVC HtmlHelper Method for Creating Buttons With Forms and Optional Images: Part 1

Straight from the "I made this and maybe you can find a use for it" bin, here is one of two ways I create image buttons. Why would you care? I have no idea, but two of the catches that comes with buttons is they have to be wrapped in a form and the fact you have to, far as I know, add hidden value inputs to the form to carry over the values from a url (Action of the form). This take care of both, can ya' belee it?

This guy takes in a url (ie you already know what it should be, say from pre determined redirect value), breaks down the url to get the request parameters to make hidden inputs, and adds the button. Now I went with the image being a style for the button instead of passing in a location for the image itself, mostly because I find that to be easier to handle from a design perspective since it's possible that particular image might be used a lot on a site. Seems easier, if you need to change the image, to change one css class then to have to search and replace a million image urls. But what do I know? No seriously, what do I know?

public static String OptionalImageButton(this HtmlHelper helper, String returnUrl, Boolean viewAsImage, FormMethod formMethod, String buttonText, String formClass, String imageClass, String buttonClass)
{
  StringBuilder html = new StringBuilder();
  //Create the form along with the formMethod passed in
  html.Append("<form action=\"" + returnUrl + "\" class=\"" + formClass + "\" method=\"" + formMethod + "\"> ");

  //This is the method from this post, it just give me all the hidden inputs from a url
  html.Append(MvcMethods.CreateHiddenValuesFromUrl(returnUrl));
  //This is where you might hate me.  Instead of having an image for the button
  //I am using a css class to hold the image.  Just a choice, makes it easier
  //in my opinion
  if (viewAsImage)
  {
    html.Append("<input type=\"submit\" value=\"\" class=\"" + imageClass + "\" />");
  }
  else
  {
    //If no image, then just put a text button.
    html.Append("<input type=\"submit\" value=\"" + buttonText + "\" class=\"" + buttonClass + " \" ></input>");
  }

  //End the form
  html.Append("</form>");

  return html.ToString();
}

You might notice the FormClass parameter, or maybe you didn't because you can't read. If that's the case, then we're both wasting time. However, if you did notice then you might find it odd. As it is, a form has to be inline in order to show buttons next to each other. After all, by default a form is a block element like a div. Therefore, the form itself will need a class or the style set. Now I could default this to inline, but for the sake of giving power to the programmer, it's left as a parameter. After all, maybe not all buttons should be inline.

And usage:

  Html.OptionalImageButton(Model.ReturnUrl, Model.UserShowImages, "Return", "inline", "returnButton", "button080SmallTextAction")

Pretty easy to use and clean... well clean for MVC at least. Next MVC post I'll show the route driven version of this "control".

Bookmark and Share
13Aug/090

ASP.Net MVC: Button Post Is Losing QueryString Values And Getting Paramters From A URL

I was going to start this post with a rousing ARE YOU READY FOR SOME PROGRAMMING?, but my lawyer suggested it might cause the NFL to take action against me. He suggested something more simple like PROGRAMMING HAPPENS HERE! since he had high doubts the NBA will sue me. After all they'd have to admit they actually came up with that f-ing slogan in the first place. It's a win/win situation for me.

So one of the things I've run into with MVC is this situation... Say I have a form and a button, and the form has an action that looks like this:

  <form action="/Tools/AddTool/1?redirect=/Tools/ViewTool/1" method="post">
    < button type="submit">GO!</button>
  </form>

Really simple. The idea is that I want to post to the AddTool action, do some stuff, then have the action redirect back to the ViewTool action. Seems like it should be easy right? Well not so much. Because when you view the ActionParameters (Like in this example) for the "redirect" key, it finds the key but loses the value. This may result in a failure if have an attribute making sure it exists or possiblly you just have it set to a default that's useless like a fourth foot. Either way, not good.

Now I haven't figured out the reason for this (Don't act so surprised, you aren't a very good actor), but I have figured out a way around it. Basically for the form to keep the values, you need to add hidden values. I know, it's a pain. Good thing I have a method that makes it easier. Also, this post is a prerequisite for a method I have for creating buttons... but that in the future. ITS A TEASER! THIS POST IS A TEASER! THERE I SAID IT! CAN I GO NOW?

public static String CreateHiddenValuesFromUrl(String baseUrl)
{
  StringBuilder html = new StringBuilder();

  if(!String.IsNullOrEmpty(baseUrl))
  {
    //Have to find the ? to know where to begin
    Int32 indexOfQuestionMark = baseUrl.IndexOf('?');

    //If the question mark exists and there is something after it, keep going
    if (indexOfQuestionMark > -1 && baseUrl.Length >= indexOfQuestionMark + 1)
    {
      //Get everything AFTER the ?, something I didn't think of first time around
      //Caused many test failures and much shame to my family.
      String request = baseUrl.Substring(indexOfQuestionMark + 1);

      //Cut up the string by the & since every parameter after the first
      //is divided by &.. I know, Duh.
      String[] splitList = request.Split('&');

      //Go through the list of possible request items
      foreach (var requestItem in splitList)
      {
        String[] splitItem = requestItem.Split('=');
        //This is to make sure the parameter actually has a value to send in
        //the hidden values.  I supposed you could create an empty hidden
        //value to preserve the parameter, but remember the parameter
        //isn't being lost from the form action, just the value
        if (splitItem.Length == 2 && !String.IsNullOrEmpty(splitItem[1]))
        {
          //Create a hidden input with the key name and the value
          html.Append("<input type=\"hidden\" name=\"" + splitItem[0] + "\" value=\"" + splitItem[1] + "\" >");
        }
      }
    }
  }

  return html.ToString();
}

And it's just that simple. Mind you I could probably make this an extension method for the HtmlHelper, but I don't really use it for that.

Next up will be more razzle and dazzle using this to make an optional image button. I bet you can't wait. I know I can.

Bookmark and Share
6Aug/090

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.

Bookmark and Share
4Aug/090

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.

Bookmark and Share
Tagged as: , No Comments
3Aug/090

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!

Bookmark and Share
Tagged as: , No Comments
28Jul/092

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.

Bookmark and Share
Tagged as: , 2 Comments
27Jul/092

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.

Bookmark and Share
Tagged as: 2 Comments
NetDevInc.com