eWorld.UI - Matt Hawley

Ramblings of Matt

Routing + WebForms + Auto “Binding” Properties

June 21, 2008 10:51 by matthaw

Just ran across this excellent post by Jeremy Skinner. Just shows on how much power & flexibility the new routing framework gives you. This really is making me want to really focus on my slack project of using Routing instead of Url Rewriting at work.



Categories:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

At a loss for blog topics

June 21, 2008 01:36 by matthaw

For the life of me, I can't seem to come up with any new blogging topics. At this point, I've exhausted all that's in MVC Preview 3, and haven't been doing anything super fun or cool at work lately. Hmmm, toss some things out and maybe I'll come up with something. Anyone?

 

On the flip side, I've fallen in love with Twitter - allows me to output my thoughts immediately.



Categories: General
Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed

Entity Framework Rant

June 10, 2008 08:54 by matthaw

<rant>

Wow, I never thought I'd hate a product so badly just starting to use it. If you've not tried out the new Entity Framework, give it a shot - but be ready to get frustrated and fast. The mere fact that I have to do half of my editing in pure XML and the other half in the designer is absurd. Why doesn't the designer support creating a new entity from my pre-loaded entity set from the database, or the ability to add a new property to my entity! Having to hop over to XML view just to add a new property is painful. I'm also all for "iterations" of code, but why is it when it's generating the model during compile time does it only give me 1 error at a time. Gar! I can't stand this - back to LINQ to SQL.

</rant>



Categories: .NET
Actions: E-mail | Permalink | Comments (4) | Comment RSSRSS comment feed

Plea for Help: WCF 404 Error

June 6, 2008 20:33 by matthaw

I'm putting out a plea for help. For some odd reason, we have a WCF service (running in IIS 6) that's using streaming and BasicHttpBinding that will return a 404 error message every time it's called from our client. Hitting the same URL on the box itself through IE renders the WSDL just fine. If you have seen this issue, please contact me. We've been struggling with this issue and have yet to find a resolution. BTW, it works great on another web server that is configured the same, and we've looked at all of the verbose logs WCF can give us. Ultimately, we're seeing the message being sent from the client, and a 404 in the IIS log, but nothing on the server logging. Thanks!



Categories: Development | .NET
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

MVC Post-Redirect-Get Sample Updated

June 5, 2008 08:56 by matthaw

I took some time to look back at my MVC Post-Redirect-Get sample and see where it could be improved as well as update it to use the MVC Preview 3 bits. What I found, is again, the core concepts didn't change that much. However, there are some new enhancements that Preview 3 gave us that makes our life a little bit easier. I'll save the full implementation for you to download and checkout yourself, but I do want to highlight some of these enhancements that made the source easier to use.

1. NameValueCollectionExtensions.CopyTo - this made it very nice for me to take all of the posted form data and copy it into the TempData so that upon a redirect, I could extract it out and put it in ViewData.

   1:  if (!BaseValidator.Validate(HttpContext.Request, validators)) {
   2:     NameValueCollectionExtensions.CopyTo(Request.Form, TempData);
   3:     TempData["ErrorMessage"] = BuildErrorMessage(validators);
   4:     return RedirectToAction("Create");
   5:  }

2. I added an extension method for IDictionary to copy between a source and destination, primarily for copying my TempData to ViewData. This way there is no need to do a manual copy of TempData objects all over the place, and is more resilient to changes and additions within your views and controller actions. I'm hoping this makes it into the MVC stack at some point so we all don't have to write this code ourselves.

   1:  public static void CopyTo(this IDictionary<string, object> source, 
   2:                            IDictionary<string, object> destination)
   3:  {
   4:      foreach (KeyValuePair<string, object> pair in source)
   5:      {
   6:          if (!destination.ContainsKey(pair.Key))
   7:              destination.Add(pair.Key, pair.Value);
   8:      }
   9:  }

The above code allows us to simply call the following line of code

   1:  TempData.CopyTo(ViewData);

3. What you'll notice, is that now all of my data is within ViewData, I can start to utilize the built-in functionality added in Preview 3 where the form controls will attempt to extract an initial value from ViewData. This mechanism really brings back the concept of ViewState, except that there is really no overhead to do this! Here's how my form now looks

   1:  <%@ Import Namespace="PRG.Controllers" %>
   2:  <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
   3:  <% using (Html.Form<ProductsController>(c => c.Submit())) { %>
   4:      <h3>Create a New Product</h3>
   5:      Name: <%= Html.TextBox("Name") %><br />
   6:      Price: <%= Html.TextBox("Price") %><br />
   7:      Quantity: <%= Html.TextBox("Quantity") %><br />
   8:      <% if (ViewData["ErrorMessage"] != null) { %>
   9:          <br /><span style="color:red"><%= ViewData["ErrorMessage"] %></span><br />
  10:      <% } %>
  11:      <br />
  12:      <%= Html.SubmitButton() %>
  13:  <% } %>
  14:  </asp:Content>

4. While this next item isn't specifically related to Preview 3, it is a change from my last sample. Previously, I was doing all of my manual validations inline on the server, and it wasn't pretty. As you've probably been reading, I've been making some improvements to the MVC Validation within MvcContrib, and I decided I'd bring in that codebase to this sample. However, to truly show the full PRG pattern, I needed my form to post and alert me that there are errors on the page rather than relying upon client side validation; so I'm simply using the validator objects & server validation. In the next coming weeks, I'll be making another update to MvcContrib to do model based validation. I'll leave this code for your viewing or other examples on my blog.

And that's the updated sample. You can downloaded the latest bits from here. Please let me know what you think and anything else you would do to change this. As each iteration of the MVC framework is released, the sample gets easier and easier! Hope you enjoy this.



kick it on DotNetKicks.com

Using SubDataItems and View User Controls in ASP.NET MVC

June 4, 2008 08:46 by matthaw

Prior to the preview 3 release of ASP.NET MVC, whenever you wanted to pass data to your view user controls, you only had the option of passing a specific object, or using it's parent's view data. This was all great, and it worked wonderfully, but the problem existed that your view user control would always be dependant upon some parent view data. ASP.NET MVC preview 3 introduced the concept of SubDataItems off of ViewDataDictionary in which you could specify a keyed ViewDataDictionary to use. This helps in the true separation of your view user controls, or child views, and will hopefully later lead into more interesting solutions such as sub-controllers. So lets get into an example.

Hold It! Yeah, we have to patch the MVC framework first before doing anything further. I've logged a bug with the ASP.NET MVC team regarding this, and it's unfortunate to say that this shouldn't have slipped through - but that's what you get without test cases. But I digress. Okay, open the MVC Preview 3 source and open the file "System.Web.Mvc/Mvc/Extensions/UserControlExtensions.cs". Go to the "DoRendering" method, and replace the if block starting on line 127 with the following:

   1:  if (controlData != null) {
   2:      instance.ViewData.Model = controlData;
   3:  }
   4:  else if (!string.IsNullOrEmpty(instance.SubDataKey)) {
   5:      instance.ViewData = context.ViewData.SubDataItems[instance.SubDataKey];
   6:  }
   7:  else {
   8:      instance.ViewData = context.ViewData;
   9:  }

 

Okay, onto the example. Say you have a product detail on your website, and you need to display the product information on the listing page as well as on the order summary page. Because we want to display the same information in the same way on each page, it leads us into using a ViewUserControl. There's other information listed on each page itself, so there is definitely no need to create or duplicate our view data model object just for display purposes. First, we should define our model.

   1:  public class Product
   2:  {
   3:      public Product(int id, string name, decimal price)
   4:      {
   5:          Id = id;
   6:          Name = name;
   7:          Price = price;
   8:      }
   9:   
  10:      public int Id { get; set; }
  11:      public string Name { get; set; }
  12:      public decimal Price { get; set; }
  13:  }

Next, let's work on our controllers. To show the true separation, I'll have both a ProductController and OrderController.

   1:  public class ProductController : Controller
   2:  {
   3:      public ActionResult Index()
   4:      {
   5:          ViewData["Category"] = "Bicycles";
   6:          ViewData["SubCategory"] = "Mountain Bikes";
   7:   
   8:          Product product = new Product(1, "16 Speed", 499.99m);
   9:   
  10:          ViewDataDictionary<Product> subViewData = 
  11:                    new ViewDataDictionary<Product>(product);
  12:          subViewData["ShippingCost"] = 24.99m;
  13:          ViewData.SubDataItems.Add("ProductData", subViewData);
  14:   
  15:          return View();
  16:      }
  17:  }
  18:   
  19:  public class OrderController : Controller
  20:  {
  21:      public ActionResult Index()
  22:      {
  23:          Product product = new Product(1, "16 Speed", 499.99m);
  24:          decimal shipping = 24.99m;
  25:          decimal tax = (product.Price * .08m);
  26:          decimal total = product.Price + shipping + tax;
  27:   
  28:          ViewData["OrderAmount"] = product.Price;
  29:          ViewData["Tax"] = tax;
  30:          ViewData["Total"] = total;
  31:   
  32:          ViewDataDictionary<Product> subViewData = 
  33:                     new ViewDataDictionary<Product>(product);
  34:          subViewData["ShippingCost"] = shipping;
  35:          ViewData.SubDataItems.Add("ProductData", subViewData);
  36:   
  37:          return View();
  38:      }
  39:  }

As you can see, within both of the controller actions, I'm creating a new instance of a ViewDataDictionary<Product> and adding it to the ViewData.SubDataItems. This will allow me to later extract that specific ViewDataDictionary when rendering the ViewUserControl. Granted, this scenario is very rudimentary - but I wanted to show that each action / view has it's own data, but wanted to show the "sharing" of the SubDataItem data. Now, we implement our ViewUserControl (I won't show the HTML for this, it's in the download though). The ViewUserControl simply needs the following

   1:  public partial class ProductInfo 
   2:          : System.Web.Mvc.ViewUserControl<Models.Product> { }

Now, in both our Index views for product & order  we can call the helper method to render our view user control. Please note that within this, we're not specifying any control data (model) but we are specifying the SubDataKey. As you've probably figured out, that SubDataKey is the key the framework uses to extract the correct ViewDataDictionary to set on the ViewUserControl when rendering. Should you not specify a SubDataKey, it'll use the parent ViewDataDictionary - so in this case, our ViewPage's ViewDataDictionary.

   1:  <%= this.RenderUserControl("~/views/shared/ProductInfo.ascx", 
   2:                             null, 
   3:                             new { SubDataKey = "ProductData" }) %>

And that's it. Of course, SubDataItems can be used for other purposes like keeping your ViewData "componentized", but the best use for this so far is so that your ViewUserControl's can live without the knowledge or sharing of parent ViewPage's or ViewUserControl's. If you'd like the source for this demo, you can download it here. It already has the patched MVC assembly. Enjoy!

kick it on DotNetKicks.com



RedirectToAction Nasty Bug in ASP.NET MVC Preview 3

June 2, 2008 22:04 by matthaw

We were converting the CodePlex application over to ASP.NET MVC Preview 3 today and found a nasty bug with RedirectToAction. In reality, the bug isn't so much around RedirectToAction, but a change they made internally to Routing. However, this seems to only happen in certain routing scenarios. Take the following routes:

   1:  routes.MapRoute("Login", "site/home/{action}",
   2:     new { controller = "session", action = "login" });
   3:  routes.MapRoute("User Info", "site/user/{action}",
   4:     new { controller = "user", action = "show" });

The problem crops up within your UserController actions when attempting to redirect to other UserController actions. For instance

   1:  public class UserController : Controller {
   2:     public ActionResult Show() { ... }
   3:     public ActionResult Create() {
   4:        return RedirectToAction("Show");
   5:     }
   6:  }

when line 4 is executed above, it attempts to redirect you to "~/site/home/foo". The reason is the change that was made is now trying to remove all the ambiguities by "assuming" things on the fly. Since the actionName overload of RedirectToAction doesn't take and doesn't supply the controller it cannot find the appropriate route. After a bit of convincing, the bug has been acknowledge but I make no guarantees if and when it'll be fixed in a future build - but in the mean time, you're stuck with

  1. Fixing the code yourself from the CodePlex source drop. This simply involves supplying the current executing controller's name in the route value dictionary.
  2. Use the RedirectToAction overload that takes both actionName and controllerName.
  3. Use my lambda expression based RedirectToAction which correctly sends both actionName and controllerName.

And, before anyone asks - why are you creating such complicated routing? Well, simple - simple routing equals a very simple application. Complex routing equals a pre-existing and well defined "RESTful based" urls that mean something when a user reads it.

kick it on DotNetKicks.com



2 quick links for your consumption

June 2, 2008 20:13 by matthaw

This is either for your consumption or mine, whatever suits you best!

  1. There's a new technical preview of Windows Live Writer available here.
  2. Use Witty for twitter on the PC, it's f'n awesome!

Ohh, by the way today was the first time that Windows Live Search was defeated in one swift blow from Google when searching for 'twhirl' (Live vs. Google) and 'witty' (Live vs. Google). Just don't keep that up Live, or I'm switching back.



Categories: General
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed


Copyright © 2000 - 2024 , Excentrics World