European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET 4.5 Hosting - Amsterdam :: AjaxControlToolkit version 7.0123 with .NET 4.5

clock April 25, 2013 06:26 by author Scott

Here’s my steps and workarounds from the very beginning (in Visual Studio 2012), hopefully some part of this will help fix whatever error you are encountering.

File -> New Project
.NET Framework 4.5
Visual C# -> Web
ASP.NET Web Forms Application
Add AjaxControlToolkit version 7.0123 (dll is actually 4.5.7.123 which is January 2013 I believe) via NuGet

Open Default.aspx
Add a calendar to the BodyContent / MainContent:

<asp:TextBox ID="myTextBox" runat="server" />
<ajaxToolkit:CalendarExtender ID="myCalendar" runat="server" TargetControlID="myTextBox" Format="dd/MM/yyyy" />

Run it up (F5 will do)

It might error about ASP.NET Ajax 4.0 scripts:
0x800a139e – JavaScript runtime error: AjaxControlToolkit requires ASP.NET Ajax 4.0 scripts. Ensure the correct version of the scripts are referenced. If you are using an ASP.NET ScriptManager, switch to the ToolkitScriptManager in AjaxControlToolkit.dll.

I’ve also seen it error about:
‘MsAjaxBundle’ is not a valid script name. The name must end in ‘.js’.

No bother, let’s remove that reference from the Site.Master, so:

<asp:ScriptManager runat="server">
    <Scripts>
        <%--Framework Scripts--%>
        <asp:ScriptReference Name="MsAjaxBundle" />
        <asp:ScriptReference Name="jquery" />
        <asp:ScriptReference Name="jquery.ui.combined" />
        <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
        <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
        <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
        <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
        <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
        <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
        <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
        <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
        <asp:ScriptReference Name="WebFormsBundle" />
        <%--Site Scripts--%>

    </Scripts>
</asp:ScriptManager>

Now becomes:

<asp:ScriptManager runat="server">
    <Scripts>
        <asp:ScriptReference Name="jquery" />
        <asp:ScriptReference Name="jquery.ui.combined" />
        <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
        <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
        <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
        <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
        <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
        <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
        <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
        <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
        <asp:ScriptReference Name="WebFormsBundle" />
    </Scripts>
</asp:ScriptManager>

Next is ToolkitScriptManager, the snippet above now becomes:

<ajaxToolkit:ToolkitScriptManager runat="server">
    <Scripts>
        <asp:ScriptReference Name="jquery" />
        <asp:ScriptReference Name="jquery.ui.combined" />
        <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
        <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
        <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
        <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
        <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
        <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
        <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
        <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
        <asp:ScriptReference Name="WebFormsBundle" />
    </Scripts>
</ajaxToolkit:ToolkitScriptManager>

But of course this fails with:
Could not load file or assembly ‘System.Web’ or one of its dependencies. The system cannot find the file specified.

Remove the Assembly=”System.Web” part from the ScriptReference so we have have:

<ajaxToolkit:ToolkitScriptManager runat="server">
    <Scripts>
        <asp:ScriptReference Name="jquery" />
        <asp:ScriptReference Name="jquery.ui.combined" />
        <asp:ScriptReference Name="WebForms.js" Path="~/Scripts/WebForms/WebForms.js" />
        <asp:ScriptReference Name="WebUIValidation.js" Path="~/Scripts/WebForms/WebUIValidation.js" />
        <asp:ScriptReference Name="MenuStandards.js" Path="~/Scripts/WebForms/MenuStandards.js" />
        <asp:ScriptReference Name="GridView.js" Path="~/Scripts/WebForms/GridView.js" />
        <asp:ScriptReference Name="DetailsView.js" Path="~/Scripts/WebForms/DetailsView.js" />
        <asp:ScriptReference Name="TreeView.js" Path="~/Scripts/WebForms/TreeView.js" />
        <asp:ScriptReference Name="WebParts.js" Path="~/Scripts/WebForms/WebParts.js" />
        <asp:ScriptReference Name="Focus.js" Path="~/Scripts/WebForms/Focus.js" />
        <asp:ScriptReference Name="WebFormsBundle" />
    </Scripts>
</ajaxToolkit:ToolkitScriptManager>

It seems the new web forms project template adds ‘Microsoft.AspNet.ScriptManager.MSAjax 4.5.6′ package, this appears to conflict with the toolkit, so remove this via “Manage NuGet Packages”
Visual Studio might still leave the dll in your bin directory even after a clean, make sure you manually clean that out.

 



European ASP.NET 4.5 Hosting Tips :: How to Improve your ASP.NET Website Performance

clock April 5, 2013 08:27 by author Scott

In this article I will sharing few tips to improve the performance in ASP.NET site. This is the things that I have done:

1. HTTP Compression

HTTP compression is used to compress page content from the server end. It compress HTTP requests and responses, so is a great performance improvement. My project is hosted in Windows Server 2003, and I implemented HTTP compression after reading this article.

2. Disable Possible ViewState

View State allows the page state to be persisted with the client, and it does not require cookies or server memory. View State saves data in a hidden input filed inside a page. Definitely, it is a powerful feature, but the drawback is it increases page size and memory allocation in the server.

So, we should avoid View State where it is not necessary. Especially, in the case of DataGrid controls, we should avoid View State as it loads all the grid data in the page state.

In my application, I disabled View State for most of the controls and pages where View State is not necessary. This made the page sizes smaller. 

3. Changes in the Web.Config File

a. Use page caching:

This will save your page only for a certain amount of time, and the page will be faster to load. But, remember that if your page data changes frequently, it is not a good idea to use page caching.

<caching>
<outputCacheSettings>
    <outputCacheProfiles>
        <add name="cached" duration="600"
            varyByParam="none" enabled="true"/>
    </outputCacheProfiles>
</outputCacheSettings>
</caching>

b.Remove unnecessary httpModules from the web.config:

<add name="ScriptModule"
     type="System.Web.Handlers.ScriptModule, System.Web.Extensions,
           Version=3.5.0.0, Culture=neutral,
           PublicKeyToken=31BF3856AD364E35"/>
<remove name="WindowsAuthentication" />
<remove name="PassportAuthentication" />
<remove name="AnonymousIdentification" />
<remove name="UrlAuthorization" />
<remove name="FileAuthorization" />

c.Turn off trace:

<trace enabled="false" pageOutput="false" />

d.As I have used membership, I disabled automatic save for profiles:

<profile enabled="true" automaticSaveEnabled="false" />

e.Set debug=false:

<compilation debug="false">

4. Optimize Stylesheets

It is important to clean up style sheets and remove unnecessary code from style sheets because it increases the load time. Remove all unnecessary classes from style sheets and try to use a single CSS file.

5. Optimize JavaScript

6. JS and CSS File Position

According to the advice from some good articles, I put the CSS file declaration at the top of my master page. It is recommended to call CSS files at the top of a page because the page rendering will progressively become efficient.

I put JavaScript file links at the bottom of the main master file. If we put scripts at the top of the page, then it will cause unnecessarily high load times.

7. Client-side Script for Validation

For page validation, I use client-side validations instead of postbacks. This way, I reduce round trips in pages.

The above are few trips to improve your ASP.NET performance.

Looking for ASP.NET hosting on European server? Please visit HostForLIFE.eu. HostForLIFE.eu is awarded Top No#1 SPOTLIGHT Recommended Hosting Partner by Microsoft (see http://www.microsoft.com/web/hosting/HostingProvider/Details/953). Our service is ranked the highest top #1 spot in several European countries, such as: Germany, Italy, Netherlands, France, Belgium, United Kingdom, Sweden, Finland, Switzerland and other European countries. Besides this award, we have also won several awards from reputable organizations in the hosting industry and the detail can be found on our official website.

 



European ASP.NET 4.5 Hosting - Amsterdam :: Create ASP.NET 4.5 File Security Process

clock March 20, 2013 07:24 by author Scott

Often when working with web applications it is necessary to secure access to documents or other user supplied resources.  If you look online you will find a number of different recommendations on how to accomplish this.  Some will recommend a HTTP Handler, some will recommend a simple ASPX, others will have other random ideas.  Regardless of the actual implementation there is always a common area of mixed recommendation, once you have validated that the user has the proper permissions to access the resource, how do you get the item to the user?  In this post I'll discuss a new API that is publicly available in .NET 4.5 that helps with one problem area.

The Problem

Determining if the user has access to the resource in question is rarely the area that causes trouble.  The problem comes with the process of serving the desired files to the user.  When you let IIS handle the serving of a file it automatically sets the Content Type on the HTTP Response to match the proper type for the file, however, if you are sitting in the middle of this process, you have to handle this yourself.

Recommendation to Solve Issue

If you look into this issue, try googleing "Determining File MIME Types" or similar.  You will find all kinds of recommendations.  They will range from creating a custom look up process based on file extension, to weird PInvoke calls into windows, or even from the really crafty individuals a reflection call to an internal member of previous versions of the .NET framework.

In the end, there has never really been a good, consistent way to handle this.  Often times if you are working with a limited subset of file types the switch statement solution will work, however, as new file types are added etc it becomes harder to manage.

New Solution

With .NET 4.5, there is a newly exposed class that can be used to solve this complicated process.  System.Web.MimeMapping is a class that has existed for a while prior to .NET 4.5 but was "internal" to the framework and could not easily be called without using reflection.  Now you can simply call a method with a file path and it will return the Content Type.

This makes it so that we can now use something as simple as the following to serve a secured document after validating that the user has permissions.

Response.Clear();
Response.ContentType =
  System.Web.MimeMapping.GetMimeMapping(Server.MapPath(document.ServerDocumentPath));
Response.AddHeader("Content-Disposition",
                    "attachment; filename=" + document.UploadedDocumentName);
Response.WriteFile(Server.MapPath(document.ServerDocumentPath));
Response.End();

As you can see here, it is just 5 lines of code. In the first line of code we clear anything that  might have already been written to the response.  In the second line we call out to MimeMapping's GetMimeMapping method providing it the filepath to our document.  The third line we are telling the browser that we want to force download the file and are specifying a custom file name.  Then in the last two lines we write the file to the response and end.

The nice thing with this approach as you can see in the above example we can have a different ServerDocumentPath than our actual document name.  This allows us to hide the files in a different manner and serve them up to users with a friendly name.

I hope this helps someone looking for a way to introduce a security process to file downloads.  This .NET framework MimeType mapping is very helpful for this type of situation.



European ASP.NET Hosting - Amsterdam :: Tips Submit Form with ASP.NET

clock March 11, 2013 06:11 by author Scott

In this article I try to explain the default submit behavior of form and panel. Suppose, you want to press/click submit button on Enter key press or you are trying to post the form on Enter key press. In asp.net, to achieve this functionality we need to set "Defaultbutton" property either in Form or in panel.

Form DefaultButton Property

     <form id="form1" runat="server" defaultbutton="btnSubmit">
    <div>
    <asp:TextBox ID="txtUserID" runat="server"/> <asp:TextBox ID="txtUserpwd" runat="server"/> <asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit _Click" Text="Submit"/>
    </div>
    </form>

Panel DefaultButton Property

     <asp:Panel ID="Panel1" runat="server" defaultbutton="btnSubmit">
    <div>
    <asp:TextBox ID="txtUserID" runat="server"/> <asp:TextBox ID="txtUserpwd" runat="server"/> <asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit _Click" Text="Submit"/>
    </div>
    </asp:Panel >

Note

1. We specify the defaultbutton property at the Form level in the form tag when there is only one Submit Button for post back.

2. We specify the defaultbutton property at the Panel level in the Panel tag when there are multiple Submit Button for post back.



European ASP.NET 4.5 Hosting - Amsterdam :: How to Enable Unobtrusive Validation Mode in ASP.NET 4.5

clock February 27, 2013 05:09 by author Scott

In this article we will learn how to enable Unobtrusive Validation in ASP.NET 4.5.

Visual Studio 2012 provides some new Validation features that include Unobtrusive Validation. When you work with this Validation mode you will find that there is not much difference in this validation and previous validations but to enable this type of validation you had to first configure your Web Application.

There are three ways to enable the Unobtrusive Validation in your Web Application; they are:

- By using Web.Config file
- By using Global.asax file
- By using Page_Load event on each page

The first method is by using the Web.Config file.

Step 1

Write the following code in your Web.Config file:

<configuration>
  <
appSettings>
    <
add key="ValidationSettings:UnobtrusiveValidationMode" value="None"></add>
  </
appSettings>
    <
system.web>
      <
compilation
 debug="true" targetFramework="4.5" />
      <
httpRuntime targetFramework="4.5" />
    </
system.web> 
</configuration>

Step 2

Now write the following code in your WebForm.aspx Page:

<asp:TextBox runat="server" ID="txt" />
     <asp:RequiredFieldValidator ID="RequiredFieldValidator1" ErrorMessage="txt is required"ControlToValidate="txt" runat="server" Text="Text is Required" Display="Dynamic" />

    <asp:Button ID="Button1" Text="Send info" runat="server" />

Step 3

Now debug your code, on debugging the code you will get the output like this:

When you click on the button in the output window you will see an Error Message. As you write in the Text Box and click again on the Button the error message will be disposed of automatically.

The second method is by using a Global.asax file.

Step 1

In the Global.asax file, first add the namespace "using System.Web.UI;".

After adding the namespace write the following code in the Application_Start method:

protected void Application_Start(object sender, EventArgs e)
{
    ValidationSettings.UnobtrusiveValidationMode =
 UnobtrusiveValidationMode.None;
}

Step 2

Now write the following code in your WebForm.aspx page:

<asp:TextBox runat="server" ID="txt" />
     <asp:RequiredFieldValidator ID="RequiredFieldValidator1" ErrorMessage="txt is required"ControlToValidate="txt" runat="server" Text="Text is Required" Display="Dynamic" />

    <asp:Button ID="Button1" Text="Send info" runat="server" />

Step 3

Again debugging your Web Application you will again get the same output as you got in the first method.

The third method is by simply writing the code on each page inside the Page_Load event.

Step 1

protected void Page_Load(object sender, EventArgs e)
{
    this.UnobtrusiveValidationMode = System.Web.UI.UnobtrusiveValidationMode.None;

}

Step 2

Now write the following code in your WebForm.aspx page:

<asp:TextBox runat="server" ID="txt" />
     <asp:RequiredFieldValidator ID="RequiredFieldValidator1" ErrorMessage="txt is required"ControlToValidate="txt" runat="server" Text="Text is Required" Display="Dynamic" />

    <asp:Button ID="Button1" Text="Send info" runat="server" />

Step 3

Again debug your Web Application and you will again get the same output as you got in the first method.

 



European ASP.NET 4.5 Hosting - Amsterdam :: How to Disable Bundling and Minification in ASP.NET 4.5/MVC 4

clock February 12, 2013 05:51 by author Scott

Lots of people are excited about the new bundling and minification feature in the next version of ASP.NET and MVC. One major drawback I see a lot of people clamoring about is the fact that you cannot conditionally disable bundling or minification when you are in debug mode. Out of the box (and to be clear, I’m referring to the version that ships with MVC 4 beta) it’s impossible to debug your CSS and Javascript.

I expect this will change in the release version, but for now you are forced to create your own custom bundles (something you’d end up doing anyway) and conditionally check if you’re in debug mode to short-circuit the bundling/minification.

Disabling minification while in debug mode

It’s as simple as an #if DEBUG line and creating a transformer that does nothing. For example:

01           protected void Application_Start()
02           {
03               IBundleTransform jsTransformer;
04           #if DEBUG
05               jsTransformer = new NoTransform("text/javascript");
06           #else
07               jstransformer = new JsMinify();
08           #endif
09          
10               var bundle = new Bundle("~/Scripts/js", jsTransformer);
11          
12               bundle.AddFile("~/Scripts/script1.js");
13               bundle.AddFile("~/scripts/script2.js");
14          
15               BundleTable.Bundles.Add(bundle);
16           }

Now when you reference this javascript bundle like <script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script> in a view it will render a single bundled and minified script when in release mode, but as a single bundled, non-minified file while in debug mode.

Disabling bundling while in debug mode

The above approach improves this situation, but I don’t think it goes far enough. If I’m going to have multiple source files, I want to debug with the same multiple source files, at least initially. It would get too confusing writing code in a several files and then debugging it in a single monolithic file.

As an experiment to see if it was possible, I ended up building a better bundler that does just what I want: bundles and minifies in release mode, but doesn’t bundle or minify when the build is set to debug.

The entire class is below, explanation to follow:

01           public static class BetterBundler
02           {
03               private static bool _debug;
04               const string CssTemplate = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />";
05          
06               public static void Init()
07               {
08           #if DEBUG
09                   _debug = true;
10           #endif
11                   var bundle = new Bundle("~/content/css", new CssMinify());
12          
13                   bundle.AddFile("~/Content/test.css");
14                   bundle.AddFile("~/Content/site.css");
15                   
16                   BundleTable.Bundles.Add(bundle);
17               }
18          
19               public static MvcHtmlString ResolveBundleUrl(string bundleUrl)
20               {
21                   return _debug ? BundledFiles(BundleTable.Bundles.ResolveBundleUrl(bundleUrl)) : UnbundledFiles(bundleUrl);
22               }
23               
24               private static MvcHtmlString BundledFiles(string bundleVirtualPath)
25               {
26                   return new MvcHtmlString(string.Format(CssTemplate, bundleVirtualPath));
27               }
28          
29               private static MvcHtmlString UnbundledFiles(string bundleUrl)
30               {
31                   var bundle = BundleTable.Bundles.GetBundleFor(bundleUrl);
32          
33                   StringBuilder sb = new StringBuilder();
34                   var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
35          
36                   foreach (var file in bundle.EnumerateFiles(new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundleUrl)))
37                   {
38                       sb.AppendFormat(CssTemplate + Environment.NewLine, urlHelper.Content(ToVirtualPath(file.FullName)));
39                   }
40          
41                   return new MvcHtmlString(sb.ToString());
42               }
43          
44               private static string ToVirtualPath(string physicalPath)
45               {
46                   var relativePath = physicalPath.Replace(HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"], "");
47                   return relativePath.Replace("\\", "/").Insert(0, "~/");
48               }
49          
50               public static MvcHtmlString CssBundle(this HtmlHelper helper, string bundleUrl)
51               {
52                   return ResolveBundleUrl(bundleUrl);
53               }
54           }

To summarize, I’m using the same technique to determine debug mode, and of course this could be extended to conditionally bundle or not based on any boolean. The interesting code is in the UnbundledFiles(string bundleUrl) method.

Currently, there is no concept of named bundles – bundles are specified simply by the virtual path of the resultant bundle. This means all our calling code in the view has to give is the virtual path of the bundle. We have to start from that and uncover all the physical files deeper within the BundleTable.

var bundle = BundleTable.Bundles.GetBundleFor(bundleUrl);

This line retrieves the bundle that we created from the BundleTable.

bundle.EnumerateFiles(new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundleUrl))

This gets all of the physical files from the bundle.

The rest is just boilerplate code to turn those raw physical files back into relative virtual paths and into the proper html tags.

Finally, you’ll note that I have an HtmlHelper method in there, CssBundle(this HtmlHelper helper, string bundleUrl). To render a bundle link in a view, this must be used. Since the result of a bundle could be one or multiple files, I decided the simplest approach would be to allow the BetterBundler to render the full html tag itself. This could easily be changed or enhanced.

1              In the view:
2             
3              @Html.CssBundle("~/content/css")

The Result

In release mode:

<link href="/content/css?v=7GiB-1k9Pr1JbbYY72bT3T2EOpxXf0rGPdEOXVKl5oQ1" rel="stylesheet" type="text/css" />

In debug mode:

<link href="/content/test.css" rel="stylesheet" type="text/css" />
<link href="/content/site.css" rel="stylesheet" type="text/css" />

 



European ASP.NET 4.5 Hosting - Amsterdam :: Web Sockets and How to Develop HTML5 Web Sockets in ASP.NET 4.5

clock December 20, 2012 05:02 by author Scott

HTML5 WebSockets allow you to perform two-way (duplex) communication between the client browser and the server. ASP.NET 4.5 and IIS 8 provide support for WebSocket protocol so that you can program WebSockets in your ASP.NET web forms and ASP.NET MVC applications. This article discusses what WebSockets are and how to develop web applications that take advantage of HTML5 WebSockets.

Overview of HTML5 Web Sockets

Typically a communication over the web is comprised of two distinct parties participating in the communication, viz. the client and the web server. An ordinary web page uses a request-response model of communication wherein the browser sends a request to the server and the server then sends back a response. Each request and response uses a new connection and that connection is closed once the response is returned by the server. As you might have guessed, such a communication is poor in terms of performance since a new connection is established between the same client and the server every time. Additionally, such a communication can't be two way, i.e. client talking to server and server talking to the client simultaneously.

In the case of two-way or duplex communication both the parties participating in the communication can communicate at the same time. A common application of the duplex communication is chat systems such as MSN or Yahoo Messenger and Google Talk. In any chat system, two or more members can chat with each other at the same time. As far as HTML5 is concerned, the technique to achieve two way communications is Web Sockets.

Unlike the request-response model, WebSockets keep the underlying communication channel open throughout the course of communication. A WebSocket based communication typically involves three steps:

- Establishing a connection between the client and the server or Hand Shake.
- Asking the Web Socket server to listen to the incoming communication
- Sending and receiving data

Web applications use HTTP protocol for their functioning and HTTP protocol essentially makes use of the request-response model. The plain HTTP protocol isn't well suited for performing two-way communications. The WebSockets therefore, need to "upgrade" the plain HTTP protocol to WebSocket protocol. This "upgrade" takes place while establishing the connection between the client and the server. In order to upgrade the communication from plain HTTP to WebSocket, you need a web server that is capable of doing this upgrade.

Enabling WebSocket Protocol in Windows 8

As far IIS is concerned, IIS 8.0 that ships with Windows 8 is capable of accepting Web Socket communications. If you are developing a web application that makes use of HTML5 Web Sockets, you may need to install WebSocket support in IIS 8.0. The following figure shows the "Turn Windows features on or off" option from the control panel. It can be used to install WebSocket protocol.



Notice how the "WebSocket Protocol" feature is checked under "World Wide Web Services". If the IIS installation doesn't have WebSocket protocol enabled your ASP.NET applications won't be able to receive and respond to the WebSocket requests on the server.

A WebSocket based application consists of two parts, viz. WebSocket server side code and WebSocket client side code. The WebSocket server side code sits on the web server and "listens" to the incoming communication from clients. When some communication is received from the client it processes the communication and typically sends some communication back to the client. If there is no communication from the client the WebSocket server can either keep waiting for the communication or can terminate the communication channel. The WebSocket client side code makes use of the WebSocket object of HTML5 for the purpose of sending and receiving data to and from the WebSocket server side code.

The WebSocket client side code follows the same coding pattern regardless of your web server software. As far as ASP.NET is concerned, IIS 8 and certain .NET framework classes together allow you to develop WebSocket server side functionality. To understand how the client side and server side code goes hand in hand let's develop a simple application that performs a two-way communication. The web form that acts as a WebSocket client is shown below:



Using the above web form you can send a text message from the client to the server. The server then sends the same message back to the client (this is purely for the sake of simplicity and testing purposes. You can send any other data from the server. Clicking on the Stop button stops the server and no further communication can take place between the client and the server.

Coding the Client Side

Open the default web form and add the following jQuery code to a <script> block:

var socket;
$(document).ready(function () {
    socket = new WebSocket("ws://localhost:1046/WebSocketGenericHandler.ashx");
    socket.addEventListener("open", function (evt) {
      $("#divHistory").append('<h3>Connection Opened with the Echo server.</h3> ');},
    false);  
    socket.addEventListener("message", function (evt) {
      $("#divHistory").append('<h3^gt;' + evt.data + '</h3> ');   },
    false);  
    socket.addEventListener("error", function (evt) {
      $("#divHistory").append('<h3>Unexpected Error.</h3> ');},
    false);
    ...
});


The code shown above declares a global variable named socket to hold a reference to a WebSocket object. A WebSocket instance is then created by passing the URL of the WebSocketHandler.ashx. The WebSocketHandler.ashx contains the WebSocket server side code that "listens" to the client requests. You will develop WebSocketHandler.ashx later in this article. Notice how the URL uses ws:// protocol instead of http://. Next, event handlers for the three events, viz. open, message, and error, are wired using the addEventListener() method. The open event is raised when the readyState property (discussed next) changes to 1 (OPEN) and indicates that the connection is ready to send and receive data. The message event is raised when a message is received from the WebSocket server. The error event is raised when an error occurs during the communication with the Web Socket server.

Inside the message event handler the data sent by the server is retrieved using the evt.data property. The returned data is then appended to a <div> element. The other event handlers simply output the specified messages in the <div> element. The data from the client is sent to the server when the Send button is clicked. The click event handler of the Send button looks like this:

$("#btnSend").click(function () {
    if (socket.readyState == WebSocket.OPEN) {
        socket.send($("#txtMsg").val());
    }
    else {
        $("#divHistory").append('<h3>The underlying connection is closed.</h3> ');
  }
});


The click event handler of the Send button checks the readyState property of the WebSocket object. If the readyState is OPEN, it calls the send() method on the WebSocket instance. This read only property returns the current state of the connection. Possible values are 0 - CONNECTING, 1 - OPEN, 2 - CLOSING, 3 - CLOSED. The send() method sends data to the WebSocket server side code over an established connection. The text entered in the textbox is passed as a parameter to the send() method.

You can close the underlying connection by calling the close() method of the WebSocket object as follows:

$("#btnStop").click(function () {
  socket.close();
});

Coding the Server Side

The WebSocketHandler.ashx contains the server side code that listens and responds to the client requests. This code is shown below:

public class WebSocketHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            context.AcceptWebSocketRequest(DoTalking);
        }
    }
    ...
}


The above code shows an ASP.NET generic handler - WebSocketHandler - that triggers the WebSocket server. The ProcessRequest() method of the generic handler first checks whether the incoming request is a WebSocket request. This is done by checking the IsWebSocketRequest property of the HttpContext object. This property works hand-in-hand with the IIS 8.0 WebSocket module and returns true if an incoming request is a WebSocket request. A Web Socket request is different than an ordinary HTTP request in that instead of using http:// protocol it uses ws:// (Web Socket) protocol.

If the IsWebSocketRequest returns true, the AcceptWebSocketRequest() method of the HttpContext is called. This method takes one parameter - user function - that supplies a function that listens and responds to the client requests. In this case the user function contains the logic to listen to the incoming data and send it back to the client. The user function supplied to the AcceptWebSocketRequest() method should be an asynchronous function as shown below:

public async Task DoTalking(AspNetWebSocketContext context)
{
    WebSocket socket = context.WebSocket;
    while (true)
    {
        ArraySegment buffer = new ArraySegment(new byte[1024]);
        WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
        if (socket.State == WebSocketState.Open)
        {
            string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
            userMessage = "You sent: " + userMessage + " at " +  DateTime.Now.ToLongTimeString();
            buffer = new ArraySegment(Encoding.UTF8.GetBytes(userMessage));
            await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
        }
        else
        {
            break;
        }
    }
}


The DoTalking() method is marked as "async" indicating that the code inside it is going to run in asynchronous fashion. The DoTalking() method returns a Task object. The Task class acts as a wrapper to the asynchronous code. The DoTalking() method receives a parameter of type AspNetWebSocketContext. The AspNetWebSocketContext class gives you access to the WebSocket through its WebSocket property. The WebSocket class is the server side counterpart of the HTML5 WebSocket object. An endless while loop is then started so that the server can continuously listen to the incoming requests. To receive the incoming data, the ReceiveAsync() method of the WebSocket class is used. The ReceiveAsync() method is invoked along with the await operator. In this case the awaited task is to receive incoming data and store it in an ArraySegment, a byte array. The results of the receive operation are stored in WebSocketReceiveResult object. If the WebSocket is open as indicated by the State property, the received data is sent back to the client using the SendAsync() method. If the State property has any value other than Open, the while loop is exited thus terminating the server.

Summary

HTML5 WebSockets allow you to perform two-way (duplex) communication. To use HTML5 WebSockets in an ASP.NET application you need to enable the WebSocket protocol in IIS 8.0. You can then use IsWebSocketRequest property and AcceptWebSocketRequest() method to start the client-server communication. Using WebSockets, you can develop web applications such as Chat systems that require the ability to send and receive data simultaneously between the client and the server.

 



European ASP.NET 4.5 Hosting - Amsterdam :: Using Caller Info Attributes in .NET 4.5

clock December 12, 2012 07:56 by author Scott

Introduction

When developing complex .NET applications sometimes you need to find out the details about the caller of a method. .NET Framework 4.5 introduces what is known as Caller Info Attributes, a set of attributes that give you the details about a method caller. Caller info attributes can come in handy for tracing, debugging and diagnostic tools or utilities. This article examines what Caller Info Attributes are and how to use them in a .NET application.


Overview of Caller Info Attributes


Caller Info Attributes are attributes provided by the .NET Framework (System.Runtime.CompilerServices) that give details about the caller of a method. The caller info attributes are applied to a method with the help of optional parameters. These parameters don't take part in the method signature, as far as calling the method is concerned. They simply pass caller information to the code contained inside the method. Caller info attributes are available to C# as well as Visual Basic and are listed below:

Caller Info Attribute

Description

CallerMemberName

This attribute gives you the name of the caller as a string. For methods, the respective method names are returned whereas for constructors and finalizers strings ".ctor" and "Finalizer" are returned.

CallerFilePath

This attribute gives you the path and file name of the source file that contains the caller.

CallerLineNumber

This attribute gives you the line number in the source file at which the method is called.


A common use of these attributes will involve logging the information returned by these attributes to some log file or trace.


Using Caller Info Attributes


Now that you know what Caller Info Attributes are, let's create a simple application that shows how they can be used. Consider the Windows Forms application shown below:


The above application consists of two Visual Studio projects - a Windows Forms project that contains a form as shown above and a Class Library project that contains a class called Employee. As you might have guessed the Windows Form accepts EmployeeID, FirstName and LastName and calls AddEmployee() method of the Class Library. Though the application doesn't do any database INSERTs for the sake of illustrating Caller Info Attributes this setup is sufficient.

The Employee class that resides in the Class Library project is shown below:


1. 
public class Employee
2. 
{
3. 
    public Employee([CallerMemberName]string sourceMemberName = "",
4. 
                    [CallerFilePath]string sourceFilePath = "",
5. 
                    [CallerLineNumber]int sourceLineNo = 0)
6. 
    {
7. 
        Debug.WriteLine("Member Name : " + sourceMemberName);
8. 
        Debug.WriteLine("File Name : " + sourceFilePath);
9. 
        Debug.WriteLine("Line No. : " + sourceLineNo);
10.
    }
11. 

12.
    private int intEmployeeID;
13.
    public int EmployeeID
14.
    {
15.
        get
16.
        {
17.
            return intEmployeeID;
18.
        }
19.
        set
20.
        {
21.
            intEmployeeID = value;
22.
        }
23.
    }
24. 

25.
    private string strFirstName;
26.
    public string FirstName
27.
    {
28.
        get
29.
        {
30.
            return strFirstName;
31.
        }
32.
        set
33.
        {
34.
            strFirstName = value;
35.
        }
36.
    }
37. 

38.
    private string strLastName;
39.
    public string LastName
40.
    {
41.
        get
42.
        {
43.
            return strLastName;
44.
        }
45.
        set
46.
        {
47.
            strLastName = value;
48.
        }
49.
    }
50. 

51.
    public string AddEmployee([CallerMemberName]string sourceMemberName="",
52.
                              [CallerFilePath]string sourceFilePath="",
53.
                              [CallerLineNumber]int sourceLineNo=0)
54.
    {
55.
        Debug.WriteLine("Member Name : " + sourceMemberName);
56.
        Debug.WriteLine("File Name : " + sourceFilePath);
57.
        Debug.WriteLine("Line No. : " + sourceLineNo);
58.
        //do database INSERT here
59.
        return "Employee added successfully!";
60.
    }
61.
    

The Employee class is quite simple. It contains a constructor, a method named AddEmployee() and three properties, viz. EmployeeID, FirstName and LastName. The caller info attributes are used in the constructor and AddEmployee() method. Notice how the caller info attributes are used. To use any of the caller info attributes you need to declare optional parameters and then decorate them with the appropriate attributes. In the above example the code declares three optional parameters, viz. sourceMemberName, sourceFilePath and sourceLineNo. Note that sourceLineNo is an integer parameter since the [CallerLineNumber] attribute gives a numeric result. The optional parameters are assigned some default values. These values are returned in case there is no caller information. Inside the constructor and AddMethod() the code simply outputs the parameter values to the Output window using Debug.WriteLine() statements.

The Employee class thus created is used by the Windows Forms application as follows:


1. 
private void button1_Click(object sender, EventArgs e)
2. 
{
3. 
    Employee emp = new Employee();
4. 
    emp.EmployeeID = int.Parse(textBox1.Text);
5. 
    emp.FirstName = textBox2.Text;
6. 
    emp.LastName = textBox3.Text;
7. 
    MessageBox.Show(emp.AddEmployee());
8. 
}

The Click event handler of the Add Employee button simply creates a new instance of the Employee class, assigns property values and calls the AddEmployee() method.

If you run the Windows Forms application and see the Output window you should see this:



The Output window shows the caller information

As you can see the Output window shows the caller information as expected.


Using [CallerMemberName] with INotifyPropertyChanged Interface


Though the primary use of caller info attributes is in debugging and tracing scenarios, you can use the [CallerMemberName] attribute to avoid using hard-coding member names. One such scenario is when your class implements the INotifyPropertyChanged interface. This interface is typically implemented by data bound controls and components and is used to notify the user interface that a property value has changed. This way the UI can refresh itself or do some processing. To understand the problem posed by hard-coding property names see the modified Employee class below:


1. 
public class Employee:INotifyPropertyChanged
2. 
{
3. 
    public event PropertyChangedEventHandler PropertyChanged;
4.  

5. 
    private int intEmployeeID;
6. 
    public int EmployeeID
7. 
    {
8. 
        get
9. 
        {
10.
            return intEmployeeID;
11.
        }
12.
        set
13.
        {
14.
            intEmployeeID = value;
15.
            if (PropertyChanged != null)
16.
            {
17.
               PropertyChangedEventArgs evt = new PropertyChangedEventArgs("EmployeeID");
18.
               this.PropertyChanged(this, evt);
19.
            }
20.
        }
21.
    }
22. 

23.
    private string strFirstName;
24.
    public string FirstName
25.
    {
26.
        get
27.
        {
28.
            return strFirstName;
29.
        }
30.
        set
31.
        {
32.
            strFirstName = value;
33.
            if (PropertyChanged != null)
34.
            {
35.
               PropertyChangedEventArgs evt = new PropertyChangedEventArgs("FirstName");
36.
               this.PropertyChanged(this, evt);
37.
            }
38.
        }
39.
    }
40. 

41.
    private string strLastName;
42.
    public string LastName
43.
    {
44.
        get
45.
        {
46.
            return strLastName;
47.
        }
48.
        set
49.
        {
50.
            strLastName = value;
51.
           if (PropertyChanged != null)
52.
            {
53.
               PropertyChangedEventArgs evt = new PropertyChangedEventArgs("LastName");
54.
               this.PropertyChanged(this, evt);
55.
            }
56.
        }
57.
    }
58. 

59.
    public string AddEmployee([CallerMemberName]string sourceMemberName="",
60.
                              [CallerFilePath]string sourceFilePath="",
61.
                              [CallerLineNumber]int sourceLineNo=0)
62.
    {
63.
       ...
64.
    }
65.
}

The Employee class now implements INotifyPropertyChanged interface. Whenever a property value is assigned it raises PropertyChanged event. The caller (Windows Forms in this case) can handle the PropertyChanged event and be notified whenever a property changes. Now the problem is that inside the property set routines the property names are hard-coded. If you ever change the property names you need to ensure that all the hard-coded property names are also changed accordingly. This can be cumbersome for complex class libraries. Using the [CallerMemberName] attribute you can avoid this hard-coding. Let's see how.

To use the [CallerMemberName] attribute to avoid hard-coding the property names you need to do a bit more work. You need to create a generic helper method that internally assigns the property values. The following code shows how this can be done:


1. 
protected bool SetPropertyValue<T>(ref T varName, T propValue, [CallerMemberName] string propName = null)
2. 
{
3. 
    varName = propValue;
4. 
    if (PropertyChanged != null)
5. 
    {
6. 
        PropertyChangedEventArgs evt = new PropertyChangedEventArgs(propName);
7. 
        this.PropertyChanged(this, evt);
8. 
        Debug.WriteLine("Member Name : " + propName);
9. 
    }
10.
    return true;
11.
}

The SetPropertyValue() method uses only the [CallerMemberName] attribute. It takes three parameters. The first reference parameter is the variable that holds a property value (strFirstName for example). The second parameter is the new property value being assigned to the property. Finally, the third optional parameter supplies the caller member name. Inside the SetPropertyValue() method you assign the property value to the variable, raises the PropertyChanged event and calls Debug.WriteLine() as before.

Now, you need to call the SetPropertyValue() method inside the property set routines as shown below:


1. 
private string strFirstName;
2. 
public string FirstName
3. 
{
4. 
    get
5. 
    {
6. 
        return strFirstName;
7. 
    }
8. 
    set
9. 
    {
10.
        SetPropertyValue<string>(ref strFirstName, value);
11.
    }
12.
}

Now when you assign any property value, the set routine will call the SetPropertyValue() method and pass its name to the SetPropertyValue() method. Inside the SetPropertyValue() method you use this name (propName parameter) without hard-coding the actual property name.

Summary


.NET Framework 4.5 introduces Caller Info Attributes that can be used to obtain information about the caller of a method. Three attributes, viz. [CallerMemberName], [CallerFilePath] and [CallerLineNumber] supply caller name, its source file and the line number at which the call was made. You can use caller info attributes for tracing, debugging, logging or diagnostic purposes.



European ASP.NET 4.5 Hosting - Amsterdam :: Using ASP.NET 4.5 to Upload Multiple Files

clock November 23, 2012 05:20 by author Scott

In versions of ASP.NET before 4.5 there was no direct way to enable a user to upload multiple files at once. The FileUpload control only supported a single file at the time. Common solutions to uploading multiple files were to use a server-side control such as those from Telerik or DevExpress or to use a client-side solution using a jQuery plugin for example. In the latter case, you would access Request.Files to get at the uploaded files, rather than retrieving them form a FileUpload control directly. Fortunately, in ASP.NET 4.5 uploading multiple files is now really easy.

The FileUpload Control with HTML5 Support

The FileUpload control has been enhanced in ASP.NET to support the HTML5 multiple attribute on an input with its type set to file. The server control has been expanded with an AllowMultiple attribute that renders the necessary HTML5 attribute. In addition, the control now has properties such as HasFiles and PostedFiles that enable you to work with a collection of uploaded files, rather than with just a single file as was the case with previous versions of the control.

All you need to do to enable multiple file uploads is set the AllowMultiple property of the FileUpload control to true:

<asp:FileUpload ID="FileUpload1" runat="server" AllowMultiple="true" />

In the browser, this renders the following HTML:

<input type="file" multiple="multiple" name="FileUpload1" id="FileUpload1" />

Notice how the multiple="multiple" attribute tells the browser to enable support for multiple files. Each browser that supports this feature uses a slight different interface. For example, in Chrome it looks like this:

while in Opera it looks like this:

All major browsers (Firefox, Chrome, Opera and Safari) except Internet Explorer 9 support this feature. IE 10 will support uploading multiple files as well, so hopefully this limitation is soon a thing of the past. While Safari seems to officially support this feature, I couldn't make the example work with multiple files. This could be a bug in Safari.

Working with the uploaded files at the server is similar to how you used to work with the control, except that you now work with a collection of files, rather than with a single instance. The following code snippet demonstrates how to save the uploaded files to disk and assign their names to a simple Label control, reporting back to the user which files were uploaded:

protected void Upload_Click(object sender, EventArgs e)
{
  if (FileUpload1.HasFiles)
  {
    string rootPath = Server.MapPath("~/App_Data/");
    foreach (HttpPostedFile file in FileUpload1.PostedFiles)
    {
      file.SaveAs(Path.Combine(rootPath, file.FileName));
      Label1.Text += String.Format("{0}<br />", file.FileName);
    }
  }
}

With this code, each uploaded file is saved in the App_Data folder in the root of the web site. Notice that this is just a simple example, and you would still need to write code you normally would to prevent existing files from being overwritten, and to block specific files types from being uploaded.

 



Europe ASP.NET 4.5 Hosting - Amsterdam :: Using Model Binding in ASP.NET Data Controls

clock September 6, 2012 09:12 by author Scott

Introduction

ASP.NET Web Forms became popular due to the wide range of data bound controls such as GridView, DetailsView and ListView. The earlier versions of ASP.NET, however, were a bit rigid about how data was bound to these controls. Most of the time developers had to use one or the other data source control (SQL Data Source, Object Data Source, Entity Data Source etc.) to bind data from the underlying data store with the data bound controls. ASP.NET 4.5 provides a flexible alternative to data bind these controls - model binding. Using the new model binding features you can use methods instead of data source controls to perform CRUD operations. This article explains how the new model binding features can be used. You will also learn to use strongly typed data controls.

Data Binding in ASP.NET Server Controls

In the earlier versions of ASP.NET you used data bound controls and data source controls hand in hand to display and edit data. First, you needed to configure a data source control, such as Object Data Source or Entity Data Source and then set the DataSourceID property of a data bound control to the respective data source control. The data bound control would have one or more fields of some inbuilt type (BoundField for example) or template fields. If the control was using template fields you used Eval() data binding expression for one way data binding and Bind() data binding expression for two way data binding.

The following sample markup shows a GridView control bound with an Entity Data Source.

<asp:EntityDataSource ID="EntityDataSource1" runat="server"
    ConnectionString="name=NorthwindEntities"
    DefaultContainerName="NorthwindEntities" EnableFlattening="False"
    EntitySetName="Customers"
    Select="it.[CustomerID], it.[CompanyName], it.[ContactName], it.[Country]">
</asp:EntityDataSource>
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
    DataKeyNames="CustomerID" DataSourceID="EntityDataSource1">
    <Columns>
        <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" ReadOnly="True"
            SortExpression="CustomerID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
            ReadOnly="True" SortExpression="CompanyName" />
        <asp:BoundField DataField="ContactName" HeaderText="ContactName"
            ReadOnly="True" SortExpression="ContactName" />
        <asp:TemplateField HeaderText="Country" SortExpression="Country">
            <EditItemTemplate>
                <asp:Label ID="Label1" runat="server" Text='<%# Eval("Country") %>'></asp:Label>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" Text='<%# Bind("Country") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>


Notice how the DataSourceID property of the GridView is set to EntityDataSource1. Also, notice the use of Eval() and Bind() to bind the Country column.


Though data source controls work well in simple situations, developers often need complete control on how the data is fetched and how it is saved back to the database. This calls for a more code centered approach than the control driven approach. That is where the new model binding features come into the picture. Using model binding features you can write methods in your code behind class that perform the CRUD operations on the underlying data store. This way you have total control over the process of fetching and editing the data. Have a look at the following markup that uses the new model binding features:

<asp:GridView ID="GridView1" runat="server"
SelectMethod="GetCustomers"
dateMethod="UpdateCustomer"
DeleteMethod="DeleteCustomer"
... >


This time the GridView control doesn't use a data source control. The SelectMethod, UpdateMethod and DeleteMethod properties are set to method names GetCustomers, UpdateCustomers and DeleteCustomers respectively. These methods reside in the code behind. You will develop a complete version of this example in the following sections.

In addition to the code centered data binding, you can also use data within the controls in strongly typed manner. This is especially handy for template fields. Instead of using Eval() and Bind() data binding expressions, you can now use Item and BindItem properties respectively. These properties work along with the ItemType property. The use of these properties will be clear from the following markup.

<asp:GridView ID="GridView1" runat="server"
SelectMethod="GetCustomers"
UpdateMethod="UpdateCustomer"
DeleteMethod="DeleteCustomer"
ItemType="NorthwindModel.Customer"
... >
<Columns>
...
<asp:TemplateField HeaderText="Country" SortExpression="Country">
  <ItemTemplate>
   <asp:Label ID="Label2" runat="server" Text='<%# Item.Country %>'></asp:Label>
  </ItemTemplate
  <EditItemTemplate>
   <asp:TextBox ID="TextBox2" Text='<%# BindItem.Country %>' runat="server"></asp:TextBox>
  </EditItemTemplate>
</asp:TemplateField>
...


Notice the code marked in bold letters. The ItemType property is set to an Entity Framework Data Model type - Customer. Once you do so, you can access properties of Customer class in a strongly typed fashion. Instead of Eval("Country") you now use Item.Country and instead of Bind("Country") you use BindItem.Country. This way there can't be any errors while specifying column names because they are available to you in the intellisense in strongly typed manner.


Creating a Sample Website

Now that you understand the basics of model binding and strongly typed data binding, let's create a web form that illustrates the complete process in detail. You will be using Customers table from the Northwind database in this example. Begin by creating a new ASP.NET Web Site. Then add an Entity Framework Data Model to its App_Code folder and create model class for the Customers table. The following figure shows the Customers model class in the Visual Studio designer




Open the default web form and place a GridView control on it. Configure the GridView to show CustomerID, CompanyName, ContactName and Country columns. Also add Edit and Delete command buttons. The following markup shows the GridView after adding these columns:


<asp:GridView ID="GridView1" runat="server"

SelectMethod="GetCustomers"

UpdateMethod="UpdateCustomer"

DeleteMethod="DeleteCustomer"

ItemType="NorthwindModel.Customer"

AllowSorting="True"

AllowPaging="True"

DataKeyNames="CustomerID" ...>

    <Columns>
        <asp:BoundField DataField="CustomerID" HeaderText="Customer ID" ReadOnly="True"
            SortExpression="CustomerID"></asp:BoundField>
        <asp:TemplateField HeaderText="Company Name" SortExpression="CompanyName">
            <EditItemTemplate>
                <asp:TextBox ID="TextBox2" Text='<%# BindItem.CompanyName %>' runat="server"></asp:TextBox>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" Text='<%# Item.CompanyName %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="ContactName" HeaderText="Contact Name"
            SortExpression="ContactName"></asp:BoundField>
        <asp:TemplateField HeaderText="Country" SortExpression="Country">
            <EditItemTemplate>
                <asp:TextBox ID="TextBox3" runat="server" Text='<%# BindItem.Country %>'></asp:TextBox>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label3" runat="server" Text='<%# Item.Country %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:CommandField ShowEditButton="True" ButtonType="Button">
        <ControlStyle Width="75px" />
        </asp:CommandField>
        <asp:CommandField ShowDeleteButton="True" ButtonType="Button">
        <ControlStyle Width="75px" />
        </asp:CommandField>
    </Columns>
...

</asp:GridView>


The following figure shows the GridView at runtime:




Notice that the ItemType property of the GridView is set to NorthwindModel.Customer and its SelectMethod, UpdateMethod and DeleteMethod properties are set to GetCustomers, UpdateCustomer and DeleteCustomer respectively. You will be creating these methods in the following sections.


Selecting Data

In order to display data in the GridView you need to write a method that fetches data from the data store and then specify it in the SelectMethod property of GridView. So, switch to the code behind and add a method named GetCustomers() as shown below:


public IQueryable<Customer> GetCustomers()
{
    NorthwindEntities db = new NorthwindEntities();
    var data = from item in db.Customers
                orderby item.CustomerID
                select item;
    return data;
}


The GetCustomers() method returns an IQueryable collection of Customer objects. Inside it fetches all of the records from the Customers table and returns them to the caller. Note that we have enabled paging in our GridView. When you enable paging for a GridView, behind the scenes it fetches only the required number of records as specified by the PageSize property.

Updating and Deleting Data

The methods UpdateCustomer() and DeleteCustomer() do the job of updating and deleting a Customer respectively. The UpdateCustomer() method is shown next:


public void UpdateCustomer(Customer c)

{
    NorthwindEntities db = new NorthwindEntities();
    var data = from item in db.Customers
                where item.CustomerID == c.CustomerID
                select item;

    Customer obj = data.SingleOrDefault();
    obj.CompanyName = c.CompanyName;
    obj.ContactName = c.ContactName;
    obj.Country = c.Country;
    db.SaveChanges();
}


The UpdateCustomer() method accepts a parameter of type Customer. At runtime, when you modify a GridView row and click the Update button, UpdateCustomer() method will be called and the corresponding Customer object is passed as its parameter. Inside, you find out a specific Customer based on its CustomerID, assign the modified values and then save the changes to the database by calling the SaveChanges() method.

The DeleteCustomer() method follows a similar method signature but internally deletes a Customer. The following code shows the DeleteCustomer() method:

public void DeleteCustomer(Customer c)
{
    NorthwindEntities db=new NorthwindEntities();
    var data = from item in db.Customers
                where item.CustomerID == c.CustomerID
                select item;
    Customer obj = data.SingleOrDefault();
    db.DeleteObject(obj);
    db.SaveChanges();
}


The DeleteCustomer() method receives the Customer being deleted as a parameter. Inside it fetches a Customer matching the CustomerID and deletes it using the DeleteObject() method.

Now, run the web form and try editing and deleting a few Customer records.

Adding Validation Support

Though the GridView is able to modify Customer data, there are no validations on the data being saved. One way to enforce the validations is to use a combination of template fields and validation controls. However, there is an easy alternative - Data Annotations.

Data Annotations are special attributes that you apply on the data model properties. They specify validation criteria such as maximum length, minimum length and specific data format (Email address, URL etc.).

To use Data Annotations add a new class in the App_Code folder and name it as CustomerValidations. The CustomerValidations class will store only validation information for the Customer class. You could have added the data annotation attributes directly to the Customer data model class but to avoid accidental overwriting during model recreation it is recommended to isolate them in a separate class.

public class CustomerValidations
{
    [StringLength(5,MinimumLength=3 ,ErrorMessage="CustomerID must between 3-5 characters!")]
    public string CustomerID { get; set; }

    [StringLength(20, ErrorMessage = "Company Name must be upto 20 characters!")]
    public string CompanyName { get; set; }

    [Required]
    public string ContactName { get; set; }

    [Required]
    [StringLength(15,ErrorMessage="Invalid country length!")]
    public string Country { get; set; }
}


The CustomerValidations class makes use of data annotation attributes such as [StringLength] and [Required]. The former attribute ensures that the entered data is within a specified maximum length. The later attribute enforces that the property value must be provided. You can also use many other data annotation attributes depending on your requirement.

As of now the CustomerValidations class is a stand alone class. You need to associate it with the Customer data model class using the [MetadataType] attribute. To do so, open the Entity Framework Data Model file (Model.Designer.cs) and add the following piece of code:

[MetadataType(typeof(CustomerValidations))]
public partial class Customer : EntityObject
{
...
}


The [MetadataType] attribute specifies the type of the class that contains validation information (CustomerValidations in this case).

Now, open the web form and place a ValidationSummary control below the GridView. Set its ShowModelStateErrors property to true. The ShowModelStateErrors property controls whether data model validation errors should be displayed in the ValidationSummary or not.

<asp:ValidationSummary ID="ValidationSummary1" runat="server"
ShowModelStateErrors="true" ... />


In addition to displaying validation errors to the end user, you should also ensure that the changed Customer details are saved in the database only if model validations are successful. To do so, modify the UpdateCustomer() method as shown below:

public void UpdateCustomer(Customer c)

{

    NorthwindEntities db = new NorthwindEntities();
    var data = from item in db.Customers
                where item.CustomerID == c.CustomerID
                select item;
    Customer obj = data.SingleOrDefault();
    obj.CompanyName = c.CompanyName;
    ...
    if (ModelState.IsValid)
    {
        db.SaveChanges();
    }
}


Notice the code marked in bold letters. The UpdateCustomer() method now checks the state of the model using the ModelState.IsValid property. If all the model validations are successful, the IsValid property will return true and only then will changes be saved to the database.


Now, run the web form again and try to enter some invalid data. You should see validation errors similar to the following figure:




Summary


ASP.NET 4.5 supports model binding that allows a more code centric approach for performing CRUD operations on the data. Instead of using Data Source Controls, you can now write methods in the code behind file that select, insert, update and delete data from the underlying data store. The SelectMethod, InsertMethod, UpdateMethod and DeleteMethod properties of data bound controls are used to specify the respective method. You can also make use of Data Annotations for performing validations on the data being entered. Thus the new model binding features provide a more flexible and powerful approach to data binding.



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in