Feed

During the last couple days I've been experimenting with MongoDB and its C# driver, cleverly written by Sam Corder. I'm investigating it as a replacement for a SQL Server database I am using in a web application that is higly community driven. This specific characteristic is the one that makes the NoSQL movement rise atop regular RDBMS systems like SQL Server or MySQL, since it is hard to mantain relational integrity in these scenarios. Other key features of MongoDB are focus on performance and scalability.

K. Scott Allen already wrote a quick intro on using the C# driver, so I used it as a tutorial for my first steps. Here are some thoughts I'd like to share on this topic:

  • I don't like being held by the verbosity of instantiating Document objects every time I want to manipulate the database, so I've written method overloads for the main operations, like Insert, Update, Find and Delete that receive a plain object and only then convert them to Document. This allows us to leverage anonymous objects in C# and makes the code cleaner:
   1:  Mongo mongo = new Mongo();
   2:  mongo.Connect();
   3:  Database db = mongo["testdb"];
   4:  var col = db["users"];
   5:   
   6:  foreach(Document d in col.Find(new { name = "John Doe"}).Documents)
   7:  {
   8:      int johnId = d["_id"];
   9:      int johnName = d["name"];
  10:  }

  The code with this implementation is available on my fork of the driver at github an will hopefully be merged with the master soon.

  • MongoDB allows storage of files in the database, as well, through the GridFS specification. The C# api is already implemented and functional. Follow an example for writing a file to the database:
   1:  void Main()
   2:  {
   3:      Mongo mongo = new Mongo();
   4:      mongo.Connect();
   5:      Database db = mongo["test"];
   6:      var collection = db["testcollection"];
   7:      GridFile file = new GridFile(db);
   8:      
   9:      using(GridFileStream fs = file.Create("mycv")) // define the file name
  10:      {
  11:          ReadWriteStream(File.OpenRead(@"C:\Data\felipelima_en.doc"), fs);
  12:      }
  13:  }
  14:   
  15:  public static void ReadWriteStream(
  16:      Stream readStream, 
  17:      Stream writeStream)
  18:  {
  19:      Byte[] buffer = new Byte[Int16.MaxValue];
  20:      int bytesRead = readStream.Read(buffer, 0, Int16.MaxValue);
  21:      // write the required bytes
  22:      while (bytesRead > 0)
  23:      {
  24:          writeStream.Write(buffer, 0, bytesRead);
  25:          bytesRead = readStream.Read(buffer, 0, Int16.MaxValue);
  26:      }
  27:      readStream.Close();
  28:      writeStream.Close();
  29:  }

Database files work just like plain Documents and will be assigned an Id upon creation. Therefore, they can be later queried just like a regular document.

This was just a quick glance over MongoDB and C# integration. I'm planning on using it on a large project and will post here my findings. More to come.

Tags: , , ,

During the last days I had to implement a custom model binding for a dynamic view model in a project I'm working on. This had me diving deep in the DefaultModelBinder implementation and how binding works in ASP.NET MVC.

Basically the request carries the data you controller action needs to perform its work. It may come from several different locations, like form variables, the query string and route data, in the form of key/value pairs, string-encoded.

Usually, the DefaultModelBinder implementation will be just fine for you and no additional work will be needed. However, there are situations where we need to tweak settings a bit. Model binding works in a associative manner, where you can assign a binder to a specific type, like this:

   1:  ModelBinders.Binders.Add(
   2:      typeof(DateTime),
   3:      new DateTimeModelBinder());

Here, we're saying that all DateTime values should be bound using the DateTimeModelBinder class. DefaultModelBinder will figure that out and call this class when it sees a property of DateTime type. We could say that it works recursivly by looking for the appropriate binder for each property. If no custom binder is found, DefaultModelBinder will take care of it anyway.

The IModelBinder interface defines a single method:

   1:  object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);

The bindingContext argument contains information about the mode (type, metadata, name, etc). All you have to do is to use the bindingContext.ValueProvider collection to retrieve the correct data for the given model and return it.

Apart from everything, I strongly recommend building the asp.net mvc source code instead of using the installer, so you can debug/step into the mvc classes. You can download the latest MVC 2 RC 2 source code from codeplex. Just do not forget to uninstall MVC from the GAC before building or you'll get ambiguous references.

Ever since I started discovering the MVC world I decided to completely forget Web Forms and actually adopt asp.net MVC as my web programming framework of choice. What's great about it is that you have complete control over the generated html output and absolute separation of business logic, presentation layer and model. It's all about convention over configuration! This is one of the reasons why I decided to learn Ruby on Rails some time ago. It is clear that the ASP.NET MVC .NET Framework 3.5 SP1 release was somewhat influenced by Rails.

One of the great things about ASP.NET MVC is model binding. K. Scott Allen wrote a great blog post with tips on binding. Basically, it collects your request data and fills up your view model with the incoming data.

There is a search pattern that the DefaultModelBinder uses to look for the data in the request. Basically you need to name your form elements with the same name of your model properties. For example:

1. The view model:

   1:  public class NewsModuleViewModel
   2:  {
   3:      [ScaffoldColumn(false)]
   4:      public int ID { get; set; }
   5:   
   6:      [DisplayName("News Date")]
   7:      [DisplayFormat(DataFormatString = "d", ApplyFormatInEditMode = true)]
   8:      [Required(ErrorMessage = "Por favor selecione uma data")]
   9:      public DateTime? Date { get; set; }
  10:   
  11:      [DisplayName("Title")]
  12:      [Required(ErrorMessage = "Por favor digite um título")]
  13:      public string Title { get; set; }
  14:   
  15:      [DisplayName("Resume")]
  16:      public string Resume { get; set; }
  17:   
  18:      [DisplayName("My Text")]
  19:      [UIHint("HtmlText")]
  20:      [Required(ErrorMessage = "Por favor digite um texto para a notícia")]
  21:      public string Text { get; set; }
  22:   
  23:      [DisplayName("Image")]
  24:      [UIHint("DbImage", null, "AspectRatio", 1.0)]
  25:      public string ImagePath { get; set; }
  26:  }

2. The form:

   1:  <form action="/uac/NewsModule/Edit/12" enctype="multipart/form-data" method="post">
   2:   
   3:  <p class="datalist-form">
   4:      <label for="Date">Date</label>
   5:      <input type="text" id="Date" name="Date" value="22/1/2010" />
   6:  </p>
   7:  <p class="datalist-form">
   8:      <label for="Title">Title</label>
   9:      <input class="text-box single-line" id="Title" name="Title" type="text" />
  10:  </p>
  11:  <p class="datalist-form">
  12:      <label for="Resume">Resume</label>
  13:      <input class="text-box single-line" id="Resume" name="Resume" type="text" />
  14:  </p>  

(I've reduced the HTML markup snippet for the sake of simplicity).

Please note that the input field name properties match the view model property names. The DefaultModelBinder will look for these names when doing the data binding!

You can even bind complex objects like lists, for example, but, in this case, you'll have to name your input fields according to the element index on the list! Eg.:

   1:  <input type="text" name="ImageList[0].FileName" size="44" />

It is really straightforward once you get used to it. Just always make sure to create a ViewModel class for you, instead of using the data classes directly (eg.: with LINQ to SQL).

If you need to bind uploaded files as well, it gets a bit more complicated. The best solution I've found so far was not to bind file input control and later retrieve the uploaded file in the controller action from the Request.Files collection.

Tags:

With ASP.NET Dynamic Data you get an entire dynamic data-driven website for free with almost no effort. Of course this has drawbacks, which is that in fact you lose some flexibility and need to do things in the way they can be done.

Recently I needed to improve the default List.aspx template GridView with some different colors and per-line selection for entry details, instead of clicking through an DynamicHyperlink. The first step was to attach an OnRowDataBound event in the grid, in order to set up on onmouseover event in the data rows:

DynamicData\PageTemplates\List.aspx:

<asp:GridView ID="GridView1" runat="server" DataSourceID="GridDataSource" EnablePersistedSelection="true" OnRowDataBound="GridView_RowDataBound">

Next, attach the event and set up the event (DynamicData\PageTemplates\List.aspx.cs):

protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        e.Row.Attributes["onclick"] = "location.href = '" + table.GetActionPath("Details", e.Row.DataItem) + "'";
    }
}

And I'ts all done. You get an entire row click selection for the entry details :)

 

ASP.NET offers a powerful built-in provider-based support for membership, roles and profile management. That means you get a fully functional set of features for free on your project just out of the box.

I've been working in order to integrate membership and profile management into a MVC application I am developing, so I had to refresh my mind on these topics. There are some gotchas around these topics that are worth sharing.

First of all, the default ASP.NET providers implementation for membership, roles and profiles are based on SQL Server database storage, so you'll have to configure one to start playing. A gotcha here is to run the aspnet_regsql tool to generate the required tables, schemas, stored procedures, etc. in order for the providers to work. Do not forget also to configure them correctly in the web.config file, including the connectionStringName and applicationName properties (very important!).

There are several resources and tutorials around the net explaining how to set up these providers to start working. For profile management, I recommend this one. Profiles are the way to go if you need to include additional information pertaining your application users, so, instead of creating a custom membership provider, get along with the default one and set up profile properties in the web.config file. These settings are then stored in the database and associated with the user that is currently logged on. It is possible to add profile data to anonymous users, also, which is great!

So, in order to integrate it with your MVC application, you can easily store and retrieve your profile properties inside your Controller with this.HttpContext.Profile["ProfilePropertyName"].

Also, do not forget to declare your property in the web.config file this way:

 <profile defaultProvider="AspNetSqlProfileProvider">
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider"
             type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             connectionStringName="tagsdConnectionString"
             applicationName="/"
                />
      </providers>
      <properties>
        <add name="ProfilePropertyName" type="System.String"/>
      </properties>
    </profile>

Handling exceptions in ASP.NET MVC is quite easy once you get to know the details surrounding the HandleError attribute. You can specify that a controller or a specific Action will handle errors and you can even choose which View to show based on the exception being thrown. Scott Guthrie wrote about this.

What he didn't tell us, is that there are some prerequisites for it to work as expected. First of all, you need to enable custom errors in the application web.config file:

<customErrors mode="On" />

Second, the order that you put the HandleError attributes will affect which View will actualy gonna be rendered at the end. I was trying to render a custom view based on an InvalidOperationException being throw on my action. The code looked like this:

   1:  [HandleError]
   2:  public class HomeController : QuavioController
   3:  {
   4:          [HandleError(ExceptionType = typeof(InvalidOperationException), View = "InvalidOpJoinRoom")]
   5:          public ActionResult JoinRoom()
   6:          {
   7:               throw new InvalidOperationException();
   8:          }
   9:  }

What happened is that the JoinRoom was returning the shared Error View, instead of the InvalidOpJoinRoom View. This happens because the HomeController contains a HandleError attribute (line 1), which overrides the JoinRoom's HandleError behavior (line 4), which should return the InvalidOpJoinRoom View.

The fix is very simple: Remove the HandleError atribute from the controller and let the actual actions define the proper error handling behavior.

Conclusion: Be aware that multiple HandleError attributes in a controller may alter the order which View evaluation is executed and then causing the final View not to be the view you were actually expecting. 

Tags:

ASP.NET MVC and IIS 6

by Felipe Lima 21/10/2009 07:01

I've been playing lately with ASP.NET MVC 2 Preview 2. I had no previous experience with this and it has been kind of a change in paradigms changing from web forms to mvc. At the same time, I feel very excited about this and believe that It is a big step forward when compared to web forms, mainly due to the separation of concerns and responsibilities.

As a drawback, It is very weird not to be able to drop ASP.NET server controls in the page. Initially, you'll feel a bit 'lost'. MVC uses a different method to render the page. You don't have the runat='server' stuff anymore so, instead, you'll have to render the page mostly based on what you have in your ViewData. It's not my objective to explain its functionality here, but you can find further information at the official MVC website. The latest release can be downloaded from CodePlex.

While testing my application in my hosting provider, I had a big headache since they have Windows 2003 Server installed, which comes with IIS 6. ASP.NET MVC requires a bit of work in order to work with IIS6, especially if your hosting provider does not have MVC installed in the GAC.

I would definitely suggest Phil Haack's blog as the first point for reference on this subject. There are two key posts regarding this issue that I followed in order to make it work.

First of all, MVC assembly needs to be deployed in the application Bin directory if it is not installed in the server. Detailed info here.

Second, you'll need to change the application routes for IIS 6 to correctly receive the requests and forward them to the controllers. Haacked.com walkthrough here.

As a last tip, I also found out that my MVC application wouldn't work if I used VS Publish tool to send it to the production server after following the two steps above. No clue why, but just copying the whole website files to the server worked fine. Weird!

Tags:

CKEditor is a great open source wysiwyg editor for the web. It was formerly called FCKEditor and, one of its previous versions contained a nice implementation for ASP.NET integration. The current version (3.0) has been completely rebuilt from scratch and does not support quick upload yet (I read in the forums it will be available in version 3.1).

I've been using the FCKEditor  2.6.3 for .NET, which includes an ASP.NET control for seamless integration. However, I could never make one of its great features to work: the ability to upload images on the fly and embed them in the text. There are some things that need to be set up before.

1. FCKEditor config file (fckconfig.js), when you download it, comes with its connectors default language to php. You need to change it to aspx:
    var _FileBrowserLanguage = 'aspx' ; // asp | aspx | cfm | lasso | perl | php | py 
    var _QuickUploadLanguage = 'aspx' ; // asp | aspx | cfm | lasso | perl | php | py  

2. Configure the folder that contains the fckeditor scripts in FCKEditor.cs (You will need to create a virtual directory in IIS with this path):

[ DefaultValue( "/fckeditor/" ) ]

public string BasePath 

3. Enable the upload connector in fckeditor\editor\filemanager\connectors\aspx\config.ascx (SECURITY WARNING: do not forget to implement authentication verification here!):

private bool CheckAuthentication()

{ return true; }

4. Configure the directory that will receive the uploaded images (same file as above) - This can be overriden in your website web.config appSettings section, creating a setting called FCKeditor:UserFilesPath

UserFilesPath = "/userfiles/";

 

This should be  everything that is needed in order to make file upload to work. See ya!

 

[UPDATE]:

For those of you that saw this working fine in your development machine but unexplainably not working on the production server, please refer to this forum post for the fix.

[UPDATE 2]:

Another issue that I found regarding the update above is that in a server, it did not fix the problem an I was getting a 'permission denied' JS error on the window.parent.OnUploadCompleted event. If that happens, try this fix (scroll to the bottom of the page for the code)

I had to temporarily disable comments on this blog due to the huge amount of automated spam comments I have been receiving lately. I'll enable captcha challenges on the comments posting and reenable it once this is done!

Sorry for the inconvenience, people. See you!

Tags: ,

If you've been on the latest news on the web development standards, you probably know that HTML version 5 is slowly being adopted by mainstream browsers, despite it has not reached its final release yet (it is still a draft). I've always been a fan of the impressive results that you can get with Adobe Flash and, since it is today present in almost 99% of the browsers, it has been almost a no-brainer for anyone that wanted to create a highly dynamic and interactive website for the last couple years. Despite its many drawbacks, Flash has managed to become almost ubiquitous and extremely popular in the web. Just to cite a few of these weaknesses:

  • It is a proprietary technology held by Adobe. This, by definition, is not good for the community, since we're all in Adobe's hands;
  • Even after 10 major releases during the last 13 years, Adobe did not managed to create a decent IDE for it, which today still relies mainly on a timeframe for movie clip creation and has poor debugging support;
  • Its programming language, ActionScript, which only recently became more robust with its version 3, is based on ECMAScript (prototype oriented), which implies loose typing and few compile time checks -> more runtime errors.

Now that HTML5 is here, we're clearly seeing that Flash is slowly and progressively losing market share, mostly because of the new canvas element introduced with this standard. Canvas allows 2D vector based drawing directly to the browser. This opens an entire new world of possibilities to web development, allowing creators to leverage the HTML 5 open standard to switch from Flash to canvas and, therefore, forcing browsers to implement it and improve rendering performance. Other elements like audio and video embedding are also planned to be available in this standard.

Performance is another topic apart that, however, cannot be ignored. Some of the latest canvas experiments in the web show that we have a severe performance reduction with canvas, when compared to Flash, especially when it comes to animations and 3D. This is something that still blows me today: How do browsers manage to have such a big performance difference? Google Chrome, which is the fastest browser i've ever seen, cannot be compared to Firefox when it comes to JavaScript performance, not to mention Internet Explorer, which must be some kind of joke of internet browsers. Even its latest version 8 did not manage to have half of the Chrome speed. I cannot understand what is so hard about JavaScript processing which makes it such a processor intensive task even for the modern browsers.

I really wish to see the web in the near future in a very different way than what we have now. With the adpotion of HTML 5 by all mainstream browsers (IE does not implement it yet), I hope we can all abandon Flash for good and focus on improving browsers performance to be able to afford with canvas the same interactivity that we have today with Flash. Besides that, I'd like to see more and more improvements to JavaScript frameworks like jQuery and hopefully, we'll enter Web 3.0 with an entire new set of web applications!

About the Author

myself
My name is Felipe Lima and I am a Software Engineer and co-founder at Quavio, a digital agency at Porto Alegre, Brazil. I am interested in technology, programming with the .Net Framework and sports. Check out my full profile.

Powered by BlogEngine.NET 1.4.5.0