Ryan LanciauxNew Media Mercenary

Beginning ASP.NET MVC 1.0 available on Amazon

August 7, 2009 by ryan

I know I've been quiet for a little bit here but wanted to point out some great news. Simone Chiaretta and Keyvan Nayyeri's book Beginning ASP.NET MVC 1.0 is available for purchase in the US on Amazon. Both Simone and Keyvan have a wealth of knowledge about the framework, so I'm really looking forward to the book. For more information check out

 




Are you a Control Freak?

March 24, 2009 by ryan

No Controls?
Since the very early ASP.NET MVC previews, the most common argument I've heard against using the framework is the lack of user controls. In my opinion, this is a mixed blessing, however, for some, this is a show stopper. What can you do to provide a rich user interface with the MVC framework, while not reinventing the wheel?

jQuery
Now you could go ahead and program a full fledged data grid or WYSIWYG editor, however, unless you have a bit of time to spare this is not the ideal solution. As most may realize, jQuery fits very nicely to fill in the gaps left by the absence of user controls. For the most part, the controls are not going to let you just drag-and-drop, type in a dataset and profit but a lot of the pain is kept to a minimum.

Examples
Ingrid

If you're looking for a data grid there are a number of options available pictured above is Ingrid. Flexigrid is another good one that people have used with the MVC framework, however, their site appears to be down at the moment.


Treeviews are available

Radio Buttons / Check Boxes

Check out the jQuery plugin database.

Getting Started
So, if you've decided you want to look more into using jQuery plugins -- a couple of tips that may make the transition a little easier:

  • Read up on what people using different languages are doing. I'm not saying that you should necessarily go out and learn Rails or CakePHP/CodeIgniter (although, it is beneficial). but at least look at the techniques that programmers from that realm of things are doing -- see how they are implementing their controls.

What tips do you have for creating robust user interfaces with the MVC framework?
kick it on DotNetKicks.com




Findlay .NET UserGroup Recap

January 27, 2009 by ryan

I had a great time tonight at the Findlay .NET User group! Thanks everyone that battled the weather to come out and hear me talk about the ASP.NET MVC Framework. As promised, I have posted the route constraint to allow only alphabetical values to be accepted as valid input for the display named message.

  routes.MapRoute("Message",

                 "Message/{action}/name/{Name}/",

                 new { controller = "Message", action = "HelloWorld", name = "" },

                 new {name="[a-zA-Z]+"}

  );


I apologize about the lapse in memory -- The regular expression needed a + at the end to signify that it was more than one character whoops :)  For more information on Routes check out Justin Etheredge's post on routing


MVC Framework Talk : Findlay .NET User Group

January 23, 2009 by ryan
I will be giving a talk on the ASP.NET MVC Framework at the Findlay .NET User Group on Tuesday, January 27th (5:30pm - 7:30pm). If you're in NW Ohio and want to learn more about the MVC framework and how to get up and running with it you might be interested. The talk is taking place at the Marathon building downtown -- 539 S. Main St., Findlay, OH - Room 106M. More information is available at the User Group site. Hope to see you there!


MVC HtmlHelper for Gravatar

November 13, 2008 by ryan

Based on a great suggestion from Ben Scheirman and Simone Chiaretta I have converted the Gravatar URL helper class into a HtmlHelper extension method. This was my first stab at making a HtmlHelper extension but it seems to be working nicely and helps me keep my code a lot cleaner. Instead saving the URL (which I would highly advise against) or doing some weird method calling acrobatics in the Controller, I can simply say <%= Html.Gravatar("email@email.com") %> inside the view.

I've added a couple different method definitions for various parameters. You can pass in just an e-mail address, an e-mail and gravatar parameters (see here for more info on gravatar parameters) or an e-mail address, gravatar parameters and html attributes. A quick usage summary is listed below (I'm using my brother Joel's gravatar in the examples)


<%= Html.Gravatar("email@email.com") %>

Base Gravatar Helper 

 

<%= Html.Gravatar("email@email.com", new  { s = "128", r = "pg" })%>

Gravatar helper with optional Gravatar Parameters

 

<%= Html.Gravatar("email@email.com", null, new  { style = "border:5px solid" })%>  

Helper with HTML attributes. Please note, this is still expecting the Gravatar parameters -- you can pass in null if you want to just grab the default image with no additional properties.

 

<%= Html.Gravatar("email@email.com", new { s = "128", r = "pg" }, new { style="border:5px solid;"})%>

Helper with both Gravatar parameters and HTML attributes

 

Anyways, I've posted the class file below. Hopefully you find it useful -- I would love to hear what your thoughts are or of any changes you would like to see.
GravatarHelper.cs (2.72 kb)




Gravatar on ASP.NET MVC

November 9, 2008 by ryan

UPDATE: See here

In the near future, I have a web project coming out that I've been working on for the past month or so. I'm not going to give too much detail on that just yet, however, in working on this project, I had to come up with a way for users to have profile images. I would rather not host these images on my server, I decided to leverage Gravatar (Globally Recognized Avatars).

There are a couple pre-existing options for dealing with gravatar in the .NET framework, however, I'm using the MVC framework -- standard ASP.NET controls are out of the question. After a brief look on the Gravatar site (specifically the page dealing with how the URL is constructed), it seemed like this would be a pretty easy task to write a class that I could use to get gravatar image paths. Below is the main part of the class I created to retrieve gravatar information based on an e-mail address:


        public static string GetGravatarURL(string email, string size)

        {

            return (string.Format("http://www.gravatar.com/avatar/{0}?s={1}&r=PG",

                EncryptMD5(email), size));

        }

 

        public static string GetGravatarURL(string email, string size, string defaultImagePath)

        {

            return GetGravatarURL(email, size) +  string.Format("&default={0}", defaultImagePath);

        }

 

        private static string EncryptMD5(string Value)

        {

            System.Security.Cryptography.MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

            byte[] valueArray = System.Text.Encoding.ASCII.GetBytes(Value);

            valueArray = md5.ComputeHash(valueArray);

            string encrypted = "";

            for (int i = 0; i < valueArray.Length; i++)

                encrypted += valueArray[i].ToString("x2").ToLower();

            return encrypted;

        }


All we're really doing is creating a URL based on the Gravatar path, an MD5 encrypted version of an e-mail address and some user specified parameters. For the methods, Size is how many pixels the image should be (up to 500) and defaultImagePath is the url to use as an alternate image if the user does not have a Gravatar image. There is a rating parameter also but for my site, I'm setting it to PG always.

This is not all that difficult but hopefully useful. I plan to continue writing examples as I make progress on the web application I mentioned.





MVC Framework Talk

August 19, 2008 by ryan
Tonight I have the privilege to be giving a talk on the ASP.NET MVC Framework at the Northwest Ohio .NET User Group! (6PM, at the HCR Manor Care building downtown)! If you interested in learning about some of the reasons for using the MVC framework along with creating a basic MVC application you might want to check it out :)


Visual Studio Theme Generator

August 7, 2008 by ryan

This is a really short post but I wanted to pass the word along. I just finished a fun little ASP.NET MVC Application to generate Visual Studio themes based off of 3 given colors. I have always felt that selecting every color to make a coherent theme is way too repetitive. This web application automatically chooses complements / contrasts based off your initial color selections (and uses jQuery to let you preview your theme before creating). I will be making another, more detailed post later that will explain how it all works but for now, check it out and let me know what you think.

 

View the application

 

 




RhinoCommons, NHibernate and ASP.NET MVC Part 4 - The MVC Application

May 26, 2008 by ryan

Finally we're to the point where we can see all our hard work come together. We have most of the hard work done but we still have a lot of ground to cover. If you haven't been following along, please check out Setting Up The Assemblies, Configuring the Application and Developing the Model.

Unit of Work

In some of my initial tests with NHibernate and ASP.NET MVC Pattern I kept seeing the benefits of having a Unit of Work or Session Per Request (that is opening and closing the NHibernate session at the begining and end of the http request respectively). To Recap a little, I started to write my own Session Per Request, however, Chad Myers pointed me to the Rhino Commons project which already implemented this. I think it's worthwhile becuase I don't really like putting NHibernate session code in my controller plus as Martin Fowler writes

A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.

Luckily, with RhinoCommons, it's pretty easy to implement this pattern (check out Ayende's post on this). In a standard web forms application, we would normally create a Global.aspx that inherits UnitOfWorkApplication. Since we're using ASP.NET MVC, however, we don't necessarily want to go that route. As Michael Hanney notes on his post on MVC and Castle we can have our Global.asax inherit from UnitOfWorkApplication.

 

    public class GlobalApplication : UnitOfWorkApplication

    {

 

        public override void Application_Start(object sender, EventArgs e

        { 

            base.Application_Start(sender, e); 

            RegisterRoutes(RouteTable.Routes); 

        }

...

     }

If you know of another way to do this, please be sure to let me know. Also, the routing still works as it normally would -- we're just running this code first to instantiate the UnitOfWork.

In our controllers we can call our reference our Hibernate repositories and classes without specifying an ISession.

        public ActionResult InsertProductGroup(string Title)

        {

            ProductGroup pg = new ProductGroup();

            pg.Title = Title;

            Repository<ProductGroup>.Save(pg);

            UnitOfWork.Current.Flush();

            return RenderView("AddProductGroup");

        }

Notice we're still flushing our data -- but it makes the controllers a LOT cleaner. Imagine if we had to instantiate and clean up our session in each controller.

One further thing, the UnitOfWorkApplication supports both short and long conversations. I'm not going to go too much into that but if your application requires keeping objects around for a couple HTTP Requests before saving to the database Long Conversation may be the way to go. See Ayende's Wiki for more on this

NHibernate Query Generator
In the first post of this series we looked at what it takes to setup NHibernate Query Generator (NHQG from here out). Now we get to use it to make some really nice looking code (in a later post, however, we'll be using LINQ to NHibernate). If we've set up the tool as mentioned in the first post (listed earlier), all we have to do is run the tool and make sure the generated code is added to the project.

NHQG lets us use a fluent interface to set filters on our Hibernate queries; this results in code that, in my opinion, is very easy to write and understand later on. If we wanted to Find one Product with a specific title, our code would look something like this:

        public ActionResult ViewProduct(string ID)

        {

            var p = Repository<Product>.FindOne(Where.Product.Title == ID);

            if (p != null)

            {

                return RenderView("DisplayProduct",

                                  p); 

            }

            return RenderView("DisplayProduct");

        }

The Where.Product.Title == ID is all from the NHQG autogenerated code. Now we actually have something to show for all our configuration and setup work. Soon, we're going to take a look at using LINQ to NHibernate instead of NHQG. In the meantime, I have checked all the code in to my svn at Assembla. My standard disclaimer on demo code applies here too :) This is just demo code for the sake of example. Some of it is far from ideal but great for learning.

Check out / update with SubVersion from the following location: http://svn2.assembla.com/svn/NHibernateTest





RhinoCommons, NHibernate and ASP.NET MVC Part 3 - The Model

May 22, 2008 by ryan

We're going to keep moving now that everything is setup (see part one for setup) and configured (see part two for configuration).

First off we are going to create our classes. The original classes and SQL tables are posted below (these may look familiar -- they are from my initial NHibernate post)


Initial Product

    public class Product

    {

        private IList<Product> _RelatedProducts;

        private IList<ProductGroup> _ProductGroups;

 

        public Product()

        {

            _RelatedProducts = new List<Product>();

            _ProductGroups = new List<ProductGroup>();

        }

 

        public virtual string ID { get; private set; }

        public virtual string Title { get; set; }

        public virtual string ImagePath { get; set; }

        public virtual string Description { get; set; }

 

        public virtual IList<Product> RelatedProducts

        {

            get { return _RelatedProducts; }

            set { _RelatedProducts = value; }

        }

        public virtual IList<ProductGroup> ProductGroups

        {

            get { return _ProductGroups; }

            set { _ProductGroups = value; }

        }

    }


Initial ProductGroup

    public class ProductGroup

    {

        public virtual string ProductGroupID { get; set; }

        public virtual string Title { get; set; }

        public virtual IList<Product> Products { get; set; }

    }


SQL Tables

CREATE TABLE [dbo].[SimpleProducts](

    [ProductID] [char](32) NOT NULL,

    [Title] [nvarchar](50) NOT NULL,

    [ImagePath] [nvarchar](300) NULL,

    [Description] [nvarchar](500) NULL

)

 

CREATE TABLE [dbo].[RelatedProductsLookup](

    [ProductID] [char](32) NOT NULL,

    [RelatedProductID] [char](32) NOT NULL

)

 

CREATE TABLE [dbo].[ProductsProductGroupsLookup](

    [ProductGroupID] [char](32) NULL,

    [ProductID] [char](32) NULL

)

 

CREATE TABLE [dbo].[ProductGroups](

    [ProductGroupID] [char](32) NOT NULL,

    [Title] [nvarchar](50) NULL


ActiveRecord Classes
In a traditional NHibernate application, we would write usually our mapping files at this time(see my other NHibernate post for more on that). Since we're using the ActiveRecord pattern, however, we can specify all our mappings inline with the classes. It is important to note that this would not be a pure domain because we're placing our mappings inside the model. Warning if you're sensitive to using Attributes this may not be the code for you...

Our classes will now begin with an ActiveRecord attribute over the class; our properties will begin with Property/HasAndBelongsToMany/etc. Please note, for the sake of the example, I'm being extremely verbose with my attributes. If your table/column names match the class/property names, some of the additional info in the attribute is not necessary.

    [ActiveRecord(Table="SimpleProducts")]

    public class Product

    {

        private IList<Product> _RelatedProducts;

        private IList<ProductGroup> _ProductGroups;

 

        public Product()

        {

            _RelatedProducts = new List<Product>();

            _ProductGroups = new List<ProductGroup>();

        }

 

 

        [PrimaryKey(Column="ProductID", Generator=Castle.ActiveRecord.PrimaryKeyType.UuidHex)]

        public virtual string ID { get; private set; }

 

        [Property(NotNull=true, Length=50, Column="Title")]

        public virtual string Title {get; set; }

 

        [Property(Length=300, NotNull=false, Column="ImagePath")]

        public virtual string ImagePath { get; set; }

 

        [Property(NotNull = false, Length = 500, Column="Description")]

        public virtual string Description { get; set; }

 

        [HasAndBelongsToMany(Table="RelatedProductsLookup", ColumnKey="ProductID", ColumnRef="RelatedProductID")]

        public virtual IList<Product> RelatedProducts

        {

            get { return _RelatedProducts; }

            set { _RelatedProducts = value; }

        }

 

        [HasAndBelongsToMany(Table="ProductsProductGroupsLookup", ColumnKey="ProductID", ColumnRef="ProductGroupID")]

        public virtual IList<ProductGroup> ProductGroups

        {

            get { return _ProductGroups; }

            set { _ProductGroups = value; }

        }

    }


    [ActiveRecord(Table="ProductGroups")]

    public class ProductGroup

    {

        [PrimaryKey(Column="ProductGroupID", Generator=Castle.ActiveRecord.PrimaryKeyType.UuidHex)]

        public virtual string ProductGroupID { get; set; }

 

        [Property(NotNull=true, Length=50, Column="Title")]

        public virtual string Title { get; set; }

 

        [HasAndBelongsToMany(Table="ProductsProductGroupsLookup", ColumnKey="ProductGroupID", ColumnRef="ProductID")]

        public virtual IList<Product> Products { get; set; }

    }


Repository Object
Another added benefit of using the Castle Active Record library is that we can use the Repository<T> for all of our object persistence. Instead of creating our own implementation of IRepository, we can write code like this to save / retrieve / update objects.

Selecting an object (our product IDs are HEX UUID's so this is not exactly accurate)

var p = Repository<Product>.Get(23); 


Saving / Updating

Repository<Product>.Save(p);


The repository is pretty nice -- we can save all of our objects outside of the domain, which makes for a much cleaner design. Next time, we'll be looking at the extremely simple MVC application powered by this model and NHibernate Query Generator. Continue to Part 4

 








© 2008 Ryan Lanciaux :: powered by BlogEngine.NET