System.Web.Helpers namespace contains useful class WebImage which is able to load an image from a stream or a file, transform it and render in browser:
Alternatively you could save the image to a file. But if you try using WebImage class in WinForms application this way you'll get an error. A short investigation with .NET Reflector shows what you have to set up static property System.Web.HttpContext.Current because WebImage.Save() method uses it to resolve file path. It checks the property for null in the very beginning and raises an exception.
Setting up looks like:
We don't need real HTTP context, so this is enough to make things work.
Programmining
Tuesday, July 19, 2011
Friday, February 11, 2011
Degradable cascading dropdown lists
There are several samples how to create cascading dropdown lists for ASP.NET MVC on the Web. But in my opinion they are overcomplicated. Manual generation of tags, JSON format to pass data from controller to view, using web services instead of usual action methods, all this is unnecessary.
At the same time it's important what users with disabled Javascript could still use cascading dropdown lists on your form.
I will show now how to obtain this.
At first the model. We will use a class Brand defined as:
The overriding of ToString() method allows us to do not explicitly pass dataValueField and dataTextField parameters to SelectList constructor in our views.
Class Repository which will support us with data has these two methods:
Car controller has two versions of Add action for GET and POST methods respectively:
The difference is only what a version for GET method does no validation. You can see what if input data passes validation brandName parameter is cleared and removed from ModelState dictionary to reset a dropdown list with brand names in the form. Of course in a real application new car object will be added to a database here.
Helper private methods are defined as:
And we need one more action method which will be called every time a value in the dropdown with brand names changes:
Now a view markup. Of course we need to add a reference to jquery.validate.min.js script in _Layout.cshtml file where references to other Javascript and CSS files are.
First part of a source of Add.cshtml is here:
Partial view ModelDropDownList looks like:
Both dropdown lists are of required CSS class, so jQuery validation plugin knows what user has to select some value in each of them.
And last but not least, Add.cshtml contains this Javascript code (this is promised second part of a source):
It means what after page is loaded
1) client-side form validation will be started and
2) changing value in the brands dropdown list will lead to AJAX call which refreshes DIV containing models dropdown list with correct markup.
If Javascript is disabled in user's browser it's still possible to select another brand, press submit button, and corresponding models will be rendered on the form.
The result looks like:
At the same time it's important what users with disabled Javascript could still use cascading dropdown lists on your form.
I will show now how to obtain this.
At first the model. We will use a class Brand defined as:
The overriding of ToString() method allows us to do not explicitly pass dataValueField and dataTextField parameters to SelectList constructor in our views.
Class Repository which will support us with data has these two methods:
Car controller has two versions of Add action for GET and POST methods respectively:
The difference is only what a version for GET method does no validation. You can see what if input data passes validation brandName parameter is cleared and removed from ModelState dictionary to reset a dropdown list with brand names in the form. Of course in a real application new car object will be added to a database here.
Helper private methods are defined as:
And we need one more action method which will be called every time a value in the dropdown with brand names changes:
Now a view markup. Of course we need to add a reference to jquery.validate.min.js script in _Layout.cshtml file where references to other Javascript and CSS files are.
First part of a source of Add.cshtml is here:
Partial view ModelDropDownList looks like:
Both dropdown lists are of required CSS class, so jQuery validation plugin knows what user has to select some value in each of them.
And last but not least, Add.cshtml contains this Javascript code (this is promised second part of a source):
It means what after page is loaded
1) client-side form validation will be started and
2) changing value in the brands dropdown list will lead to AJAX call which refreshes DIV containing models dropdown list with correct markup.
If Javascript is disabled in user's browser it's still possible to select another brand, press submit button, and corresponding models will be rendered on the form.
The result looks like:
Wednesday, February 9, 2011
Adding a row filter to System.Web.Helpers.WebGrid
ASP.NET MVC 3 web grid doesn't have a row filter out of the box but it could be easily added in case of need.
Suppose we have such model:
Passing it to a view with the markup showed below
gives this output
We use autocomplete attribute to tell browser do not store previously used filters thus drop-down list won't hide the grid. Also we have attached onchange event handler which will submit the form every time we change the filter value.
Unfortunately if rows in the grid are sorted somehow, applying a filter resets this order. To keep sort order during form submit we should add two hidden inputs:
To obtain necessary values we make use of SortFieldName, SortColumn, SortDirectionFieldName and SortDirection properties of WebGrid class.
As these field values are passed to WebGrid automatically we need only add filter parameter to controller method and use it, for example, in Enumerable.Where() method:
The grid with applied filter looks like:
WebGrid control is smart enough to add current filter value to URLs in grid's header, so sorting doesn't reset filter!
Suppose we have such model:
Passing it to a view with the markup showed below
gives this output
We use autocomplete attribute to tell browser do not store previously used filters thus drop-down list won't hide the grid. Also we have attached onchange event handler which will submit the form every time we change the filter value.
Unfortunately if rows in the grid are sorted somehow, applying a filter resets this order. To keep sort order during form submit we should add two hidden inputs:
To obtain necessary values we make use of SortFieldName, SortColumn, SortDirectionFieldName and SortDirection properties of WebGrid class.
As these field values are passed to WebGrid automatically we need only add filter parameter to controller method and use it, for example, in Enumerable.Where() method:
The grid with applied filter looks like:
WebGrid control is smart enough to add current filter value to URLs in grid's header, so sorting doesn't reset filter!
Friday, February 4, 2011
Unobtrusive validation attributes and ViewContext.FormContext
ASP.NET MVC 3 has a new interesting feature called unobtrusive client validation. For more detailed information you may read an article by Brad Wilson. But in short it means what for an annotated model property like:
HTML helpers render such markup:
and no Javascript code is included into the page except links to external files jquery.js, jquery.validate.js and jquery.validate.unobtrusive.js.
The important thing is what all these attributes with validation rules are rendered only if ViewContext.FormContext property is initialized. It could be done with Html.BeginForm() method called in the beginning or, if you prefer using <form> tag, manually:
You should also avoid situations like the one discussed here: No unobtrusive validation if Html.BeginForm in layout template
HTML helpers render such markup:
and no Javascript code is included into the page except links to external files jquery.js, jquery.validate.js and jquery.validate.unobtrusive.js.
The important thing is what all these attributes with validation rules are rendered only if ViewContext.FormContext property is initialized. It could be done with Html.BeginForm() method called in the beginning or, if you prefer using <form> tag, manually:
You should also avoid situations like the one discussed here: No unobtrusive validation if Html.BeginForm in layout template
Wednesday, February 2, 2011
Valid hash algorithm names for Crypto.Hash method
For unknown reason an algorithm parameter of System.Web.Helpers.Crypto.Hash method is a string instead of an enumeration value.
To learn which algorithms are available you can try using some unusual name and get InvalidOperationException: The hash algorithm 'md51' is not supported, valid values are: sha256, sha1, md5 message.
So, for example, the code
gives
You can check what calculated MD5 hash is the same as here.
Using this method is much simpler than using classes from System.Security.Cryptography namespace, though the latter provides such hash algorithms as AES, RC2, RSA etc.
To learn which algorithms are available you can try using some unusual name and get InvalidOperationException: The hash algorithm 'md51' is not supported, valid values are: sha256, sha1, md5 message.
So, for example, the code
gives
You can check what calculated MD5 hash is the same as here.
Using this method is much simpler than using classes from System.Security.Cryptography namespace, though the latter provides such hash algorithms as AES, RC2, RSA etc.
Monday, January 31, 2011
Sort indicator in System.Web.Helpers.WebGrid
ASP.NET MVC 3 has a new long expected native class System.Web.Helpers.WebGrid which is highly customizable and could be used in a number of different scenarios. Among other the grid is able to automatically sort data by selected column.
I would like to show how to add a sort indicator near the column title. It's not too difficult, but as I know, can't be done by configuring WebGrid itself. This sample is using new Razor view engine.
This markup
renders to:
As you can see column titles are linked to the same page but these links now have two extra parameters sort and sortdir which are considered by WebGrid during rendering process. These parameters are mapped to SortColumn and SortDirection properties respectively. Thus we can check if data is sorted, determine selected column using jQuery selector and add a little triangle to it's title:
The indicator will look like this:
This sample of course could be expanded for real world usage.
I would like to show how to add a sort indicator near the column title. It's not too difficult, but as I know, can't be done by configuring WebGrid itself. This sample is using new Razor view engine.
This markup
renders to:
As you can see column titles are linked to the same page but these links now have two extra parameters sort and sortdir which are considered by WebGrid during rendering process. These parameters are mapped to SortColumn and SortDirection properties respectively. Thus we can check if data is sorted, determine selected column using jQuery selector and add a little triangle to it's title:
The indicator will look like this:
This sample of course could be expanded for real world usage.
Thursday, December 16, 2010
Randomize with LINQ
Once my colleague showed me a nice way to randomize table records:
I tried to use this trick with LINQ:
but unfortunately it doesn't work. The cities weren't randomized at all. It turned out what during SQL query generation Guid.NewGuid() was treated as a constant and was ignored as the same for all records.
So the right way in this case is to call AsEnumerable() first:
Another interesting thing is what enumerating ci now gives different results every time, so this code might give wrong result:
other might contain first element anyway because records are randomized during second use of ci variable. To avoid this side effect we need to "freeze" elements with ToList():
After that the result will be as expected.
I tried to use this trick with LINQ:
but unfortunately it doesn't work. The cities weren't randomized at all. It turned out what during SQL query generation Guid.NewGuid() was treated as a constant and was ignored as the same for all records.
So the right way in this case is to call AsEnumerable() first:
Another interesting thing is what enumerating ci now gives different results every time, so this code might give wrong result:
other might contain first element anyway because records are randomized during second use of ci variable. To avoid this side effect we need to "freeze" elements with ToList():
After that the result will be as expected.
Subscribe to:
Posts (Atom)