Showing posts with label asp.net mvc. Show all posts
Showing posts with label asp.net mvc. Show all posts

Thursday, November 5, 2009

Load a Xap file from Binary

Recently I was faced with a situation where I needed to load a .xap file from a database and preview the file using Silverlight. Typically, to display a Silverlight app hosted in a web site, one would use the
tag. A detailed description of how to use this with all the available parameters can be found here.

The .xap file, which is really just a compressed package of all the necessary bits needed to run a Silverlight application, typically is stored in the file system and is referenced using the src attribute of the tag. So right there is the problem. Our .xap files are not stored in the file system, but rather in binary fields in our SQL Server 2008 database. The src property is a string indicating the path and file name of the .xap package. Argh.

To deal with this, what was needed is a way to reference the .xap file (stored in the database) with a relative url. A Silverlight application has a mime type of application/x-silverlight. This is important to note because of an interesting way one can use an .aspx page to render binary content. Prior to this, I had used an .aspx page to render jpeg images from a binary stream. Basically, this is done by clearing the response content completely in the code-behind of the page and writing the bits to the response content stream. Set the content-type and your good to go.

Well, as it turns out, this technique not only works for images, but *any* binary format that has an associated mime type. A comprehensive list of mime types can be found here. In the case of images, to set the image source to a binary file stored in a database all you do is create a page as I described and then set the src property to the url of that page. So let's say you want to retrieve an image from your database and render it using an img tag and the url of your page is ../mySite/ImageLoader.aspx. You could call the page passing it the id of the record you want to load and render the image like so:
<img src="..mySite/ImageLoader.aspx?imgId=42" />

That's it. Simple.

See where I'm going with this? How is that different from:


<object type="application/x-silverlight-2"
data="data:application/x-silverlight," width="450" height="220">
<param name="source" value="../mySite/ImageLoader.aspx?xapId=42"/>
object>



Answer: It's not. Just have the page set the content type to application/x-silverlight and you are good to go. For reference, here's the code that rewrites the output stream:

int bufferSize = 1024 * 100; // load 100KB at a time
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
long bytesToRead;
MemoryStream ms = new MemoryStream(src.ToArray());

// src is the binary file to read. How you load that is a story for another day

bytesToRead = src.Length;
Response.ContentType = this.GetContentType(filetype);
try
{
while (bytesToRead > 0)
{
if (Response.IsClientConnected)
{
bytesRead = ms.Read(buffer, 0, bufferSize);
Response.OutputStream.Write(buffer, 0, bytesRead);
Response.Flush();

bytesToRead -= bytesRead;

// re-initialize the buffer and counter
bytesRead = 0;
Array.Clear(buffer, 0, buffer.Length);
}
else
{
// make sure to break out of the loop if the client disconnects prematurely
bytesToRead = -1;
}
}
}
catch (Exception ex)
{
string err = ex.Message;
Response.Write("" + ERROR_READING_FILE + "");
}
finally
{
if (ms != null)
{
ms.Close();
}
}


Monday, March 2, 2009

Using RenderPartial() to Recursively Display Data

Scenario: You have hierarchical structure with n number of levels. This data must be displayed in nested divs/tables/lists.

Using the ASP.NET MVC framework (currently at RC1), this can easily be achieved using partial views. Here's the jist of it:

In the .aspx view page:

<% foreach(Thing parent in ViewData.Model) { %>

<% Html.RenderPartial("ThingControl", parent); %>
<% } %>

And then in the partial view:


<!-- display single item here -->

<% if (parent.children.Count > 0){ %>
<% Html.RenderPartial("ThingControl", parent); %>
<% } %>


So the exit condition for the recursion is when parent.children.Count is zero. You can include some styling to indent the nested levels if you want, or not. It's very flexible. Once again, ASP.NET MVC proves it is miles above ASP.NET 2.0.

Thursday, December 4, 2008

Single Table Inheritance With LINQ

For a while now I've been using LINQ in my ASP.NET applications and it has been a huge time saver. Having used nHibernate prior to this, the prospect of not having to deal with config files was a double bonus. One thing I do miss from nHibernate, however is the ability to add a simple Where clause in the class definition. For example, I regularly use a deleted flag in tables so as to avoid doing 'hard' deletes. In the nHibernate world, in order to exclude deleted records the config file would use something like this:
<class name="Core.ELSField, Core" table="dbo.tblFields" Where="fDeleted=0">

I've yet to find anything in the LINQ world that equates to this so I'm left including 'where !deleted' in all my queries. Oh well.

Inheritance in nHibernate is handled through discriminator columns and looks like this:

<class name="IPayment" table="PAYMENT">
<id name="Id" type="Int64" column="PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="String"/>
<property name="Amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
...
</subclass>

</class>

For the longest time, I was coding the equivalent LINQ version by hand. Little did I know that the O/R designer in Visual Studio handles this. MSDN provides a very nice example which you should be able to apply to your own situation. Hopefully you will find it as useful as I did.

Thursday, October 23, 2008

Mvc Framework Model Binders

In the preview 5 version of the asp.net mvc framework they introduced the ModelBinder. The team at my company actually started a very similar implementation for use with nHibernate. Unfortunately, it - like the project - never really took off. So along comes the mvc framework and the ModelBinder. Preview 5 supports built in support for basic binding, but allows you to build your own custom binding. 

As I mentioned in a previous post, I'll be a little different and post this example using vb.net code. Truth to be told, I prefer C#, but there seems to be a real lack of vb.net examples so far. 

To add custom binding/serialization support for your custom class it needs to implement IModelBinder. There's only one required method to implement which is GetValue() in which you take the form from the controllerContext.HttpContext.Request object and map the fields to your class. Here's a sample:


<modelbinder(GetType(fedloanrule))> _

Partial Public Class FedLoanRule

  Implements IModelBinder

    Public Function GetValue(ByVal controllerContext As System.Web.Mvc.ControllerContext, ByVal modelName As String, ByVal modelType As System.Type, ByVal modelState As System.Web.Mvc.ModelStateDictionary) As Object
  Implements System.Web.Mvc.IModelBinder.GetValue

        Dim request As HttpRequestBase = controllerContext.HttpContext.Request
        Dim rule As FedLoanRule = New FedLoanRule()

        rule.LoanType = request("LoanType")
        rule.LateDisbInterval = Integer.Parse(request("LateDisbInterval"))
        rule.MaxCombinedDepLoan = Integer.Parse(request("MaxCombinedDepLoan"))
        rule.MaxCombinedGradLoan = Integer.Parse(request("MaxCombinedGradLoan"))
        Return rule

    End Function
End Class


When an instance of a FedLoanRule is passed into my controller action, GetValue is called first. This would be useful if you had some special mapping that had to be done since it takes the mapping code out of your save/update code. In this simple case it would seem that it would have been easier just to call TryUpdateModel(). But this is good for an example. 

When the code gets into the controller action, the updated object instance is there and ready to use. Here's the catch. As of the Preview 5 version (I say that because the beta was just released),  this only seems to be useful for creating new records. If you want to do an update, even though your object is bound to the form prior to reaching your controller action, once in the controller action the Model does not see that anything has been changed. You have to retrieve the object from the model, make your change and then you can do the update. If you just call SubmitChanges()  on the object that is passed in from GetValue(), nothing is submitted. 

While it's cool functionality, it doesn't seem to make a whole lot of sense to have separate methods for inserting new records - a scenerio in which the model binder does work - and for updating existing records. 

Hey, this is still preview code and I've yet to try out the beta. Somebody else brought up this point on ScottGu's blog. And he mentioned that it might be addressed in the beta. 

ASP.Net MVC Framework

We've been using the new mvc framework at my company since the Preview 2 version. For those who are keeping score the beta was released about a week ago. I've been fortunate to have been able to work on projects that have spanned the evolution of this framework and had to upgrade a couple so I thought I'd share some of the highlights.

Let me state for the purpose of full disclosure that I've only been doing web development for about a year and a half though I've been an application developer for over 10 years now. But it's been a very full year and a half as I've been very fortunate to work for a company that embraces new technology. 

First of all, the mvc framework, certainly not a new idea having been around for some time, is a relief from having to deal with web forms. One of the biggest headaches of trying to incorporate javascript, for example, in a web forms app was having to use the ClientId property of html elements and pass that id back to the server rather than just using the id that I assign. This illustrates what seems to be the key feature that one would look to when considering switching development frameworks. With web forms the focus is on the server processing. Anytime you want to do client side processing you'll more than likely have to do some work around / hack to get it to work. It's not so much that the mvc framework gives you new functionality that web forms doesn't. It's the fact that you don't have to fight tooth and nail to get simple things to work. 

For example, take any web forms application and view the source of a page. You'll find all the nasty looking element ids that are auto generated along with html that, if you were the developer, would leave you scratching your head wondering where it came from. Now take that same page written using the mvc framework and you'll see ... wait for it ... yep, pretty much the same html that the developer wrote. You have control of every single tag that is written. 

Here's another gem. You have a datagrid control and you want to include a checkbox column. And to each checkbox you want to assign a custom attribute. Go ahead and try it. I'll wait. Hopefully when you get back here you won't have pulled out all your hair after you notice that each checkbox is enclosed in a span tag and your custom attribute is not assigned to the checkbox, BUT TO THE SPAN! Somebody with more experience please explain that to me. That same exercise using the mvc framework involves either using the Html.Checkbox helper function or just simply writing the input tag yourself and assigning whatever attribute you want. I'd call it What You Write Is What You Get. And while the world certainly doesn't need another acronym, if you try saying WYWIWYG a few times you'll soon be reverting to an Elmer Fud voice and rolling on the floor as I am right now. 

Excuse me.

Ok, I'm back.  If you want further information regarding the mvc framework, I'd check out Scott Guthrie's blog. One thing that does seem to be lacking, at least for now, is a good set of VB.Net examples. I say this because I'm currently working on an application for a client that requires VB.net and having heavily relied on example code to learn this new framework, I spent a lot of time trying to convert some of the features. Admittedly, though, much of the difficulty in conversion was dealing with LINQ and not specifically the mvc framework. I'll post some of the more interesting examples another time.