Welcome to MSDN Blogs Sign in | Join | Help

Should my database calls be Asynchronous?

Long running/expensive database calls might seem like a natural candidate for asynchronous calls. Suppose you have the following system:

  • A web application running on IIS 7 /.NET Framework v3.5 SP1 using the default request gating (maxConcurrentRequestsPerCPU="12")
  • Your server is a dual.
  • You are not using asynchronous methods.
  • Your web application contains a mix of static content, quick running dynamic pages, and a few very slow pages that hit the DB. (The DB is the bottleneck on these slow pages.)

With the above configuration, you are limited to 24 concurrent requests. While your web server can easily handle the average work load, under bursty conditions, you end up with 30 concurrent calls to the slow DB pages. Once the DB pages tie up the 24 threads (which are not doing useful work, they are just waiting for the DB to respond), all new requests are queued and your customers are waiting, even though your CPU is free. This may sound like the perfect time to use asynchronous calls, but there are a couple of problems. The maxConcurrentRequestsPerCPU setting does request gating, so converting the slow DB calls to async won’t help (without changing this setting). If you do convert these slow methods to async, you should follow the IIS/ASP.NET performance guru Thomas Marquardt’s advice and set maxConcurrentRequestsPerCPU = "5000" and maxConcurrentThreadsPerCPU="0".

Rather than convert your blocking DB calls to asynchronous, you can use thread gating by setting maxConcurrentThreadsPerCPU=30. Now when this same app is hit by 30 concurrent slow DB requests, it will have 30 threads free to serve up the cheaper requests. It’s a lot easier to change this setting than to convert your working DB code to use asynchronous approaches.

The IIS thread pool can often handle many more simultaneous blocking requests than a database server. If the database is the bottleneck, asynchronous calls will not speed up the database response. Without a throttling mechanism, efficiently dispatching more work to an overwhelmed database server by using asynchronous calls merely shifts more of the burden to the database. If your DB is the bottleneck, asynchronous calls won’t be the magic bullet. You need to add spindles or make your queries more efficient.

Required reading:

If you observe that the “ASP.NET Applications\Requests in Application Queue” performance counter is non-zero, you definitely have a performance problem. (From Thomas’s Blog).

Posted by ricka0 | 0 Comments

Tips on getting your ASP.NET MVC questions answered quickly

When you run into an issue or have a question about ASP.NET MVC the best place for it is the MVC Forum.  When you write your question, there are a few simple things that you can do to make it easier for the ‘experts’ to answer (and hence to get an answer quicker!).

1. Mention what environment you’re running in

  • What web server are you using

Most likely, you are using either “Cassini” (the test web server built in Visual Studio), IIS6 (XP), or IIS7 (on Vista, Windows 7 or Windows Server 2008).  In many cases it makes a relevant difference, so it’s good to mention it.

  • What MVC release are you using

The official release of MVC is version 1. The latest preview is MVC 2/Preview 2. There are also various preview bits and samples that you can download from Codeplex.  Just mention exactly what you are using.  If you’re using some preview bits, you can include a link to them to them to remove any ambiguity.

  • Mention which version of the .NET Framework you’re using, e.g. 3.5, 3.5 SP1, 4.0 Beta 2.

2. Try to isolate the issue

If an issue you see in a complex scenario can also be seen in a simpler scenario, it is always better to report it on the simpler scenario.  It makes the question shorter and easier to read, as it keeps it focused on the essential. You will get your question answered much quicker if you can reproduce the problem with the simplest possible code. More likely than not, you'll figure out the problem when you make the simple repro.

3. Take a quick look at the MVC FAQ and search before asking. Replace zWidget with your search word in http://forums.asp.net/search/SearchResults.aspx?q=zWidget+AND+sectionid%3a1146&o=DateDescending You might try searching stackOverflow

 

4. Include complete stack traces

If you’re getting an error in the browser, make sure you include the full stack trace that you see in there, and not just the text of the error.  Looking through a stack trace can reveal some important clues about the issue. If you don't get a stack trace, make sure you disable Step Into Just My Code.  A stack trace is shown below.

Server Error in '/' Application.

Attempted to divide by zero.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.DivideByZeroException: Attempted to divide by zero.

Source Error:

Line 16:         public ActionResult About() {
Line 17:             int x = 0, y = 1, z;
Line 18:             z = y / x;

Line 19:             return View();
Line 20:         }

Source File: s:\rm\MvcStackTrace\MvcStackTrace\Controllers\HomeController.cs    Line: 18

Stack Trace:

[DivideByZeroException: Attempted to divide by zero.]
   MvcStackTrace.Controllers.HomeController.About() in s:\rm\MvcStackTrace\MvcStackTrace\Controllers\HomeController.cs:18
   lambda_method(ExecutionScope , ControllerBase , Object[] ) +40
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +178
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +24
   System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +52
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +254
   System.Web.Mvc.<>c__DisplayClassf.<InvokeActionMethodWithFilters>b__c() +19
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +192
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +392
   System.Web.Mvc.Controller.ExecuteCore() +138
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +39
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +34
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +138
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +44
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +7
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8678910
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155



Version Information: Microsoft .NET Framework Version:2.0.50727.4200; ASP.NET Version:2.0.50727.4016
Posted by ricka0 | 0 Comments

MVC FAQ

Technorati Tags:

Please post corrections/submissions to the MVC Forum. Include MVC FAQ in the title.

Post LINQ to SQL To SQL Questions here  Post Entity Framework Questions here

Q: How do I get started with MVC?

MVC 2/Preview 2 Blogs:

There are three major new features in MVC 2, and several smaller ones (and bug fixes, of course).

Areas is a feature which allows segmentation and separation of your application, so that application features can be developed in isolation from one another (either in a single project or several).

Templated Input Helpers is a feature which can auto-generate forms and editors for your models, including allowing you to override templates (for example, if you always want dates edited on your site to include a drop-down Javascript calendar).

Pluggable Validation with Client-Side Validation Support allows users to get client-side validation support with jQuery Validation and DataAnnotations attributes out of the box, and supports a pluggable API to replace both client-side and server-side pieces.

You can see the ASP.NET MVC 2 Roadmap on our CodePlex site.

Stephen Walther on ASP.NET MVC

Q: Why was Default.aspx removed from MVC 2?
A: Default.aspx file should only be needed when running in IIS6 or in IIS7 Classic Mode. Neither Cassini (the built in VS web server) nor IIS7 Integrated Mode (the default) need default.aspx. The reason we took Default.aspx out is that there are many steps required to get ASP.NET MVC to work on IIS6 and IIS7 Classic Mode and having Default.aspx in the project doesn't help very much anyway since there are so many other steps.

Q: MVC is not working with GridView/ListView
A: ASP.NET MVC does not support data sources and does not support the GridView. If this is your preferred method of programming, you should use ASP.NET WebForms.

Q: MVC or Web Forms?

Q: ViewData v. tempData

  • http://www.squaredroot.com/2007/12/20/mvc-viewdata-vs-tempdata/
  • http://stackoverflow.com/questions/313572/what-is-tempdata-collection-used-for-in-asp-net-mvc
  • http://stackoverflow.com/questions/173159/difference-between-viewdata-and-tempdata
  • http://forums.asp.net/p/1486424/3482503.aspx

  • Q:How do I figure out route order?
    A:Use Phil Hacck's route debugger - Also see Manually unit testing routes in ASP.Net MVC

    Q: What is the correct way to write a delete action?
    A: See

    Q: How do I bind my model to a List?
    A: See Phil's blog Model Binding To A List http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

    Q: My jQuery/JSON works fine on my machine, but doesn't work on the server.
    A: Your URLs are not getting resolved correctly. See http://forums.asp.net/p/1486162/3484734.aspx

    Q: How can I find memory leaks and profile memory usage of my MVC app?
    A: Use the CLR Profiler: http://www.microsoft.com/downloads/details.aspx?FamilyId=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en  
    Thomas M. has a nice blog of how to use the profiler with ASP.NET: http://blogs.msdn.com/tmarq/archive/2007/06/09/the-clr-profiler.aspx

    Q: I have a view where the user fills out a form, submits and the data is displayed on a confirmation page. They must submit the confirmation page before the DB is updated (or their credit card is charged). The problem is, the confirmation page is nothing but text; so when they submit that View, nothing will be passed to the controller. The controller has no way of knowing what information the user entered 2 views ago.
    A: The easiest thing to do would be to shove it into Session (if Session is enabled).  Otherwise use hidden input fields or the Html.Serialize() helper from Futures.  Absolutely do not use TempData for this.  Hidden form fields is the right answer for scalability reasons. TempData is the wrong reason because if the user refreshes the confirmation page, then the TempData will be destroyed. Also, if Session is disabled, then the default TempData provider is also broken (since it's based on session).

    Q: Is there a way to precompile MVC application including code and views for deployment?
    A: You need to install the Visual Studio Web Deployment add-in (see http://www.microsoft.com/downloads/details.aspx?FamilyId=0AA30AE8-C73B-4BDD-BB1B-FE697256C459&displaylang=en)  In your MVC solution, right click on the MVC project and select "Add Web Deployment Project..." (thanks to Jacques) --- running the command line utility using aspnet_compiler will also do the job. The command line is:(framework directory)\aspnet_compiler -v /virtualDirName outputdirectoryName

    Q: I'm using partial views and jQuery. When I use jQuery to do the post and updates to the page my javascript fires as I would expect. If i let Ajax.BeginForm handle it the javascript doesn't execute. Why?
    A: When you update the DOM with new HTML, the browser doesn't automatically execute scripts in the new bit of HTML. MVC Ajax helpers would need to parse the partial HTML and try and execute the scripts, which is tricky and something we don't currently do.
    One approach you could take is to look at jQuery live events. - source http://forums.asp.net/t/1440121.aspx

    Q: How do I mix Web Forms and MVC?
    A: see http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc and http://www.hanselman.com/blog/PlugInHybridsASPNETWebFormsAndASPMVCAndASPNETDynamicDataSideBySide.aspx
    Mixing ASP.NET Webforms and ASP.NET MVC http://media.wiley.com/assets/1539/15/professionalaspnet35mvc_chapter13.pdf
    Free Sample Chapter — Chapter 13: Best of Both Worlds: Web Forms and MVC Together

    Q: Is it possible use an enums in a controller action method?
    A: Yes - See http://forums.asp.net/t/1440432.aspx

    Q: What does the following do:
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
    A:  Tells the routing engine to ignore request that end in .axd or .aspx (.aspx needed for MVC on IIS6)

    Q: Invalid viewstate exception when using AntiForgeryToken error on Hosted site.
    A: You can read more here: How To Fix the: “Validation of viewstate MAC failed” Error (ASP.NET MVC)

    Q: Can open generic methods be used with controlers?
    A: Do you mean an open generic method, such as:
    public class MyController : Controller {
        public ActionResult SomeAction<T>(T myParameter) { ... }
    }

    Or a method that is generic on a class:
    public class MyController<T> : Controller {
        public ActionResult SomeAction(T myParameter) { ... }
    }

    Example #1 is not supported in ASP.NET MVC because we don't know the type of "T". Example #2 is technically supported in MVC since by the time we get to the method we already know what the "T" is. However, the default controller factory in ASP.NET MVC cannot construct generic classes. If you have a controller factory that can create MyController<T> then ASP.NET MVC can call the action method on it.

    Q: How do I use HttpContext.Cache.Add with MVC?
    A: Overriding the OnActionExecuting method in the controller is the correct thing to do. The constructor of the controller is way, way too early. At that point MVC itself barely even knows what's going on. By the time the OnActionExecuting method executes you can get a lot more info about what's going on, including the ControllerContext, which is where the Cache property hangs off of.

    Q:How do I parse string into javascript date object based on locale? (Globalization)
    A: See http://forums.asp.net/t/1481185.aspx and http://stackoverflow.com/questions/817046/what-about-script-globalization-of-microsoftajax-js-in-asp-net-mvc  (see next Q/A)

    Q: How do I pass localized dates as query strings?
    A: The problem with automatically parsing dates from the query string with the user's locale is that we have no idea where they came from. If the server is putting dates into URLs, it clearly can't do that using the user's locale, because then you will have non-canonical URLs (and worse, URLs which point to the wrong content depending on the user's locale). In fact, even if the date came from the user, you're still generating a non-canonical URL which the user could pass along to another user and inadvertantly send them to the wrong place.
    When the values come from POSTed form fields, we know they came from the user and can then apply the user's locale when binding. - from http://forums.asp.net/t/1461209.aspx

    Q:how do I generate a URL for AJAX?
    A: var myUrl = '<%= Url.Action("GetDetails","Home"); %>';

    $.ajax({
      type: "POST",
      url: myUrl });

    see http://forums.asp.net/t/1461234.aspx

    Q: There are 2 views in my mvc app that show a list of items. Both provide the ability to edit them by redirecting to a Edit view. How can I provide a back link on the Edit form that takes the user back to the list they were on?
    A: create a hidden field in Edit view and save the UrlReferer in it. On postback use this field value to track the back address.
    <%=Html.Hidden("UrlReferer",Request.Form["UrlReferer"]??Request.UrlReferer.ToString())%>
    http://forums.asp.net/t/1461072.aspx

    Q: How do I reference scripts?
    A: <script src="<%= Url.Content("~/Public/Scripts/RunActiveContent.js") %>" type="text/javascript"></script>
    CDN is the best approach:  (see Microsoft Ajax CDN and the jQuery Validation Library )
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.js" type="text/javascript"></script>

    Q: How do I get started on jQuery with MVC?

    Q:What's the difference between temp data, view data and session data?

    Q: How do I pass data on a redirect?
    A: TempData - see http://blogs.teamb.com/craigstuntz/2009/01/23/37947/

    Q: L2S or EF?
    A:http://dotnetaddict.dotnetdevelopersjournal.com/adoef_vs_linqsql.htm

    Q:Is browser still connected? if the browser is still connected before attempting to return results or doing more work?
    A:There aren't very many reliable way of detecting this state. You can try to make it a bit better by writing some JavaScript that detects when the browser navigates away and sends a quick message to the server to tell it to stop the long operation. This method is unreliable, though, since if the user shuts down their browser or unplugs their computer the server won't get the message. The hard part is how does the server correlate the long-running process with the new message and know that they are the same.

    Q: Why do I get the following error?
    FileStream will not open Win32 devices such as disk partitions and tape drives. Avoid use of "\\.\" in the path.
    A: COM1, COM2, COM3, COM4, LPT1, LPT2, CON, AUX, PRN are reserved file names, rename your view (append X) and starting with ASP.NET 4, you can rename the action back to the reserved name via:

    [ActionName("con")]
    public string  conX() {
    return "From string ActionResult conX()";
            }

    See http://blog.bitquabit.com/2009/06/12/zombie-operating-systems-and-aspnet-mvc/

    Q: Return File does not work with non-US-ASCII
    A: That is a limitation in ASP.NET MVC (file name must be US-ASCII )  and we will try to address it in an upcoming release. See more details here (and a workaround): http://forums.asp.net/t/1448041.aspx  and http://forums.asp.net/t/1483316.aspx  - This is documented in Controller.File Method (String, String, String) (System.Web.Mvc)

    Q: why doesn't "return javascript("alert(hello);") work? 
    A:For the JavaScript result to work in an action method the action method must be executed via an AJAX request. In other words, you can't have a regular link tag that points at this action method. You have to create a special link using Ajax.ActionLink or using Ajax.BeginForm.

    Q: How do you pass parameters using RedirectToAction?
    A: You can pass parameter as GET parameters  or using TempData. TempData is better solution in most cases.
    http://www.augi.cz/programovani/aspnet-mvc-passing-data-when-redirecting/
    http://forums.asp.net/t/1470201.aspx

    Q:How do I localize  Data annotations, ErrorMessageResourceName, ErrorMessageResourceType
    A: See http://forums.asp.net/t/1433699.aspx

    Q: How do I replace the error message ""A value is required" with my own custom error message?
    A: See http://stackoverflow.com/questions/646270/asp-net-mvc-custom-validation-message-for-value-types/1374653#1374653

    Q: How do I move sessionID from the default (cookie) to the querystring?
    A: See http://forums.asp.net/t/1480365.aspx

    Q: How do I keep track of wrong answers on a form submit (limited guesses on security question)?
    A: See http://forums.asp.net/p/1476843/3460584.aspx

    Q:I'm setting the value of a hidden with tempData, but the value is always overridden on postback. What's the problem?
    A: On postback, all input helpers -- including hidden -- render the value that's in ModelState rather than the value that's provided from ViewData or the helper method. The assumption is that if you're re-rendering the form on postback, then it's because there was an error, and we should show the values the user typed rather than the values in the object. See http://forums.asp.net/p/1476843/3460584.aspx
    In your controller action, you could remove the hidden value from ModelState to force it to use the new value.

    Q: I want to pre populate some of the form fields from browser cookies. How to set and load cookies in an mvc app?
    A: The same way as in any ASP.NET application - via Cookies property on Request and Response objects. These objects are accessible from controller via HttpContext.Request and HttpContext.Response properties. So just use HttpContext.Request.Cookies and HttpContext.Response.Cookies from your controller. See http://forums.asp.net/t/1482840.aspx

    Q: XHTML header indentation format is not respected for some tags - why?
    A: In the default MVC template the <head> tag in the Site.master file (in the ~/Views/Shared folder) is marked as runat="server". This special attribute gives the tag additional behavior that in some cases is nice, and in other cases it can cause formatting problems. You can remove the runat="server" attribute from the <head> tag but that can cause certain URLs to map incorrectly. The following will not work

    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

    You’ll have to call Url.Content() instead, like we do for javaScript files. The only thing you lose at that point is Design View in VS (it’ll work but you won’t see the CSS styles). see http://forums.asp.net/t/1482073.aspx 

    Q: How do I prevent Invalid viewstate exception when using AntiForgeryToken?
    A: See http://forums.asp.net/t/1479165.aspx

    Q: How do I create  Cascading Drop Down boxes in MVC?
    A: http://stackoverflow.com/questions/705540/asp-net-mvc-cascading-drop-down

    Q: Authorize filter and what it exactly does.
    A: See http://forums.asp.net/t/1382315.aspx

    Q: How do I create a custom role provider for MVC?
    A: See http://forums.asp.net/t/1382315.aspx

    Q: How do I keep track of posts to security questions (wrong answer) to limit a client to N guesses?
    S: See http://forums.asp.net/p/1476843/3438217.aspx

    A: Routing links - see http://forums.asp.net/t/1476922.aspx

    Q: How do I enable MVC on IIS5.1 (XP) or IIS 6?

    Q: How do I use JSON in MVC?
    A: See http://weblogs.asp.net/mehfuzh/archive/2009/04/28/using-of-json-result-in-asp-net-mvc-1-0.aspx

    Q: I have an Ajax.ActionLink that loads a partial view into a div, using a get method. The problem is, the user can just visit controller/AjaxAction directly, like they could with any action method. Basically, I need an ActionMethod that accepts HttpVerbs.Get, but can only be called by Ajax; as opposed to being called as a normal action.
    A: check if Request.IsAjaxRequest() is true or false.  If it is false, you could redirect somewhere else for example.  If it is true, then continue processing.You could even create a custom action filter that checks this and makes the decision.

    Q: In WebForms, I use Page.Request.ServerVariables["LOGON_USER"];  to get the current logged in user. How do I do this in MVC?
    A: Have the controller put it in ViewData.  (thanks paul.vencill )
    ViewData["username"] = User.Identity.Name;

    Q: How do I prevent a user from sending us confidential data (credit card number, SSN, etc.) over an unsecured channel (HTTP)?
    A: You can't. If the user sends confidential data via HTTP you can't go back in time and undo the transmission. Action methods that handle posts of confidential data should use the [RequireHttps] Attribute;  the action method will ignore the post and force the sender to use HTTPS.

    Q: Will the [RequireHttps] Attribute prevent Man in the Middle Attacks (MITM) or DNS cache poisoning attacks?
    A: The [RequireHttps] Attribute can't prevent MITM or DNS cache poisoning attacks, but HTTPS in general does protect against these.

    Q: Why do I get the following build error: The "xxx" task failed unexpectedly.  System.UnauthorizedAccessException: Access to the path 'C:\Path...' is denied.
    A: You're probably hitting a known bug related to source control systems which leave your source files as read-only by default (like TFS). The first copy succeeds because there isn't anything there, but the second copy fails because it refuses to overwrite the read-only copies of the files from the first time around. There is no work-around today besides checking out all the files that will be copied so that they're read-write instead of read-only.

    Q: How do I use MVC with LiveID ?
    A: Write your own Authorize filter. See http://forums.asp.net/t/1487782.aspx

    Q: How do I fix the following error: "A potentially dangerous Request.Form value was detected from the client "
    A: See http://forums.asp.net/t/1487699.aspx

    Q: MVC App rendering in IE ok, but not in Firefox, Chrome, and Safari
    A: The Site.Master page's DOCTYPE was set to STRICT. I changed it to Transitional, and now the pages render the same in all browsers. See http://forums.asp.net/p/1484722/3489894.aspx

    Q: How do I check which event caused a post back?
    A: See http://forums.asp.net/t/1488333.aspx

    Q: How does MVC get indexed from search engines if the URL's are not file base?
    A: See http://forums.asp.net/t/1490362.aspx

    Q: How do I display data from my master page?
    A: You can use RenderAction from inside of a MasterPage. Just make an action and associated partial view for whatever it is you want to render in the Master Page. see http://forums.asp.net/t/1490283.aspx

    Posted by ricka0 | 0 Comments

    Client Side Validation for MVC 2 P2

    MVC 2 Preview 1 added support for DataAnnotations. In my MSDN article How to: Validate Model Data Using DataAnnotations Attributes I covered the basics of validation. Preview 2 adds client validation with the addition of one line of code. The following class contains the model I use in my sample download.

    public class Pals {
           [Required()]
           [Range(33,99)]
           public float Height { get; set; }
           [Required()]
           [StringLength(7)]
           public string Name { get; set; }
           [ScaffoldColumn(false)]
           public int ID { get; set; }
           public bool cool { get; set; }
           [DataType(DataType.EmailAddress)]
           [RegularExpression(@"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$")]
           public string email { get; set; }
           [DataType(DataType.MultilineText)]
           public string Bio { get; set; }
       }

    Only two minor additions are required to get client side validation. Add the jQuery and jQuery.Validate scripts for client download and call Html.ClientValidationEnabled before Html.BeginForm(). I like to use the CDN reference to jQuery and add it to my Views\Shared\Site.Master file. All my views can take advantage of client side validation without referencing the script files directly. Because it's a CDN, once the scripts are downloaded from any URL, they are in the local client cache.

    The following snippet shows my additions to the Views\Shared\Site.Master file.

    <%--     Add CDN jQuery validation scripts--%>
    <%--jQuery Debug  use jquery-1.3.2.min.js for Release --%>
    <script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.js" type="text/javascript"></script>
    <%--jQuery Validation Debug; Use jquery.validate.min.js for release --%>
      <script src="http://ajax.microsoft.com/ajax/jquery.validate/1.5.5/jquery.validate.js" type="text/javascript"></script>
        <script src="<%= Url.Content("~/Scripts/MicrosoftMvcJqueryValidation.js") %>" type="text/javascript"></script>
    

    My updated sample uses the new EditorForModel templated helper. The Edit markup is shown below.

    <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
        Inherits="System.Web.Mvc.ViewPage<MvcSimpObj.Models.Pals>" %>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    
        <h2>EditforModel</h2>
        
    <% Html.ClientValidationEnabled = true; %>
        <% using (Html.BeginForm()) { %>
            <fieldset>
                <%= Html.ValidationSummary("Broken stuff:") %>
                <%= Html.EditorForModel() %>
                <input type="submit" value="  Submit  " />
            </fieldset>
        <% } %>
      <% Html.RenderPartial("linksPalsID"); %>
    </asp:Content>

    The line  <% Html.ClientValidationEnabled = true; %>  just before the BeginForm enables client side validation.  Tabbing out of an input box instantly displays the validation error to the side of the control. You can use Fiddler or FireBug to verify the validation is client side.

    The following image displays client side error messages. Notice the validation summary is empty, the validation summary occurs on the server side. You can correct the email alias (a@bb.com for example) and it will instantly remove the validation error, even before you tab out of the input control.

    Posted by ricka0 | 0 Comments

    Attachment(s): ClientValMVC.zip

    DRY-ing out the MVC 2 Templated Helpers

    In my MSDN article  Using Templated Helpers to Display Data, I show how they provide a very productive means of building a UI for data sets. The code below shows a typical use of the Display and Label helpers.

    <span style="font-weight:bold;">
    <%= Html.Label("Name") %>
    :</span>
    <%=  Html.Display("Name") %>
    
    <br/><span style="font-weight:bold;">
     <%= Html.LabelFor(Pals => Pals.ID)%>
     :</span>
     <%= Html.DisplayFor(Pals => Pals.ID)%>
     
    <br/><span style="font-weight:bold;">
    <%= Html.LabelFor(Pals => Pals.Height)%>
    :</span>
     <%= Html.DisplayFor(Pals => Pals.Height)%>
    
    <br/><span style="font-weight:bold;">
      <%= Html.LabelFor(Pals => Pals.cool)%>
      :</span>
     <%= Html.DisplayFor(Pals => Pals.cool)%>
    
    <br/><span style="font-weight:bold;">
    <%= Html.LabelFor(Pals => Pals.email)%>
    :</span>
     <%= Html.DisplayFor(Pals => Pals.email)%>
    
    
    <br/><span style="font-weight:bold;">
     <%= Html.LabelFor(Pals => Pals.Bio)%>
     :</span>
     <%= Html.DisplayFor(Pals => Pals.Bio)%>

    What I didn't like was the DRY violation; so I wrote a helper class that allows me to pass a field expression once.  Essentially I need a helper that will return Label(expression) + middle HTML + Display(expression). The following snippet solves this problem with added flexibility.

    public static class LabelEditorExtensions {
           const int _sbCap = 512;
    
           public static string LabelEditor(this HtmlHelper html, string expression, string postLblPreDisplay) {
               return html.Label(expression) + postLblPreDisplay + html.Editor(expression);
           }
    
           public static string LableEditorFor<TModel, TValue>(this HtmlHelper<TModel> html,
            Expression<Func<TModel, TValue>> expression, string postLblPreDisplay) where TModel : class {
               return LableEditorFor(html, expression, String.Empty, postLblPreDisplay, String.Empty, _sbCap);
           }
    
           public static string LableEditorFor<TModel, TValue>(this HtmlHelper<TModel> html,
             Expression<Func<TModel, TValue>> expression, string preLbl, string postLblPreDisplay,
             string postDisplay) where TModel : class {
               return LableEditorFor(html, expression, preLbl, postLblPreDisplay, postDisplay, _sbCap);
           }
    
           public static string LableEditorFor<TModel, TValue>(this HtmlHelper<TModel> html,
              Expression<Func<TModel, TValue>> expression, string preLbl, string postLblPreDisplay,
              string postDisplay, int sbCap) where TModel : class {
    
               StringBuilder sb = new StringBuilder(preLbl, sbCap);
               sb.Append(html.LabelFor(expression));
               sb.Append(postLblPreDisplay);
               sb.Append(html.EditorFor(expression));
               sb.Append(postDisplay);
               return sb.ToString();
           }
       }

    Now I can write my view code in the DRYer method shown below.

     <span style="font-weight:bold;">
    <%= Html.LabelDisplay("Name"," :</span>")%>
    
    <br/><span style="font-weight:bold;">
       <%= Html.LabelDisplayFor(Pals => Pals.ID," :</span>")%>
     
    <br/><span style="font-weight:bold;">
    <%= Html.LabelDisplayFor(Pals => Pals.Height," :</span>")%>
    
    <br/><span style="font-weight:bold;">
      <%= Html.LabelDisplayFor(Pals => Pals.cool," :</span>")%>
    
    <br/><span style="font-weight:bold;">
    <%= Html.LabelDisplayFor(Pals => Pals.email," :</span>")%>
    
    <br/><span style="font-weight:bold;">
     <%= Html.LabelDisplayFor(Pals => Pals.Bio," :</span>")%>

    Purists (and the Visual Studio Editor) won't approve of passing HTML into the helper method. (Visual Studio reports my span tag is not terminated because it has no way of knowing my LabelDisplay helper call will return the closing span.)

    Because I'm a lazy programmer and I often repeat the same HTML pattern between my properties, I added a couple lazy helpers  to reduce the above snippet to the following:

    <%= Html.LabelDisplayForSB(Pals => Pals.Height)%>
        <%= Html.LabelDisplaySB("Name")%>
        <%= Html.LabelDisplayForSB(Pals => Pals.cool)%>
        <%= Html.LabelDisplayForSB(Pals => Pals.ID)%>
        <%= Html.LabelDisplayForSB(Pals => Pals.email)%>
        <%= Html.LabelDisplayForSB(Pals => Pals.Bio)%>

    I also have a lazy helper version that uses tables, giving the nice appearance shown below.

    When using the Editor templated helpers you have an additional call to ValidationMessage, forcing you to repeat your property one more time. Because there is currently no ValidationFor helper, I had to steal some internal source to roll in the Validation message. The snippet below shows only two of the six properties, but gives you an idea of un-DRYness:

    span style="font-weight:bold;">
    <%= Html.Label("Name")%> 
    :</span>
    <%= Html.Editor("Name")%> 
    <%= Html.ValidationMessage("Name", "*") %>
    <br/>
    
    <span style="font-weight:bold;">
    <%= Html.LabelFor(Pals => Pals.Height)%>
    :</span>
    <%= Html.EditorFor(Pals => Pals.Height)%>
    <%= Html.ValidationMessage("Height", "*")%>
    <br/>

    The complete lazy helper version shown below is much easier to read and maintain.

    <%= Html.ValLableEditorForTD(Pals => Pals.Name)%> 
    <%= Html.LabelDisplayForTD(Pals => Pals.ID)%>
    <%= Html.ValLableEditorForTD(Pals => Pals.Height)%>
    <%= Html.LableEditorForTD(Pals => Pals.cool)%>
    <%= Html.ValLableEditorForTD(Pals => Pals.email)%>
    <%= Html.LableEditorForTD(Pals => Pals.Bio)%>

    The image below shows the DataAnnotations driven validation error from the code above.

    A complete sample is included with my Label/Editor/Display integration helper (see Attachment below). I provide the Expression overloads for my helpers and a few string based helpers.

    Posted by ricka0 | 0 Comments
    Filed under: ,

    Attachment(s): Lbl4Ed4.zip

    Using DataAnnotations in MVC 2 - Catching up to Dynamic Data

     

    UnexpectedError

    DataAnnotations help you write robust validation and prevent the type of annoying error message shown above. Form submittal failure when a field doesn’t validate can be very frustrating -  especially when there is no indication of the problematic property or the constraint violation. I happened to get the Outlook error above when I attempted to submit a mail message to the MVC QA guys. It turns out the distribution list I made for them a few days earlier had problems.

    The image below (From my sample while editing the Products table) provides much better feedback.

    Validation

    In my MSDN article How to: Validate Model Data Using DataAnnotations Attributes, I cover the basics of validation using the System.ComponentModel.DataAnnotations DLL.  DataAnnotations is not new to ASP.NET, Dynamic Data has been using it since v1, but it is new to MVC.

     

    When Visual Studio 2010 is released, you’ll be able to use the richer .Net 4 DataAnnotations with MVC. DataAnnotations are a perfect fit to the MVC philosophy of SoC because data constraints are applied to the data model, not in the UI. The .Net 4 version of DataAnnotations adds 11 new attributes you can apply.

    Posted by ricka0 | 0 Comments
    Filed under: ,

    New Templated Helpers Improve SoC

    SoC (from WikiPedia)
    In my MSDN article Walkthrough: Using Templated Helpers to Display Data I show how to annotate your data model to specify that a field should be rendered with a type-specific control.  The download sample code also includes a control using the new Html.EditorFor helper. With one line of code you can open an editor on your strongly typed object. Using the line below, my edit/create view can instantiate an editor on the Product object.

    <%= Html.EditorFor(Product=> Model)%> 

    The automatic scaffolding works great for POCO objects; with EF classes the additional EDM properties are added and also scaffolded. The image below shows some of the fields of the Product table in the AdventureWorksLT sample database.

     

    EFartifacts

    We really don’t want to be displaying IsFixedSize  (changing the check box state won’t persist the metadata anyway), Length, Rank and other EDM metadata that are not fields in the Product table. Analogous to the DisplayTemplates directory I talk about in my MSDN article, you create a Product.ascx control in the Views\Home\EditorTemplates directory. The

     <%= Html.EditorFor(Product=> Model)%>

    line will automatically use the Views\Home\EditorTemplates\Product.ascx template.  Additionally, the same line of code works in both the edit and create views. The snippet below shows a Product template. (Note: I omitted most of the fields in the snippet below, the download is more complete.)

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MvcTmpHlprs.Models.Product>" %>
    
    <% using (Html.BeginForm()) { %>
        <fieldset>
    <div><%= Html.LabelFor(c => Model.Name)%> 
        <%= Html.EditorFor(c => Model.Name)%>
        <%= Html.ValidationMessage("Name", "*") %>
    
       <%= Html.LabelFor(c => Model.StandardCost)%>
     <%= Html.EditorFor(c => Model.StandardCost)%>
     <%= Html.ValidationMessage("StandardCost", "*")%>
     </div><div>
     </div><div>
       <%= Html.LabelFor(c => Model.ListPrice)%>
     <%= Html.EditorFor(c => Model.ListPrice)%>
     <%= Html.ValidationMessage("ListPrice", "*")%>
     </div><div>
     
      <p> <input type="submit" value="Save"/> </p>
        </fieldset>
        
    <% } %>

    Error Messages and Debugging

    DataAnnotations are your first line of defense for validating input. See my related DataAnnotations blog and my MSDN article How to: Validate Model Data Using DataAnnotations Attributes. The sample code shows how well DataAnnotations integrate with the new templated editor.

    For security reasons, you generally don’t want to catch and display an exception. If two users try to add “Widget 99” to the Products table, the second submit will fail because the product name has unique key constraint. The download sample shows the error message “SqlException: Violation of UNIQUE KEY constraint 'AK_Product_Name'. Cannot insert duplicate key in object 'SalesLT.Product'.” I consider that an excellent error message for a programmer, but it’s not friendly to the end user.  One approach is to catch common exceptions like this, parse the message and try to give the user a hint.

    Model errors mask the internal error message for security reasons. The sample has the following code to help you figure out the problem in a debug/development environment (For security reasons, don’t use this for production code.)

    foreach (var modelState in ModelState.Values) {
        foreach (var error in modelState.Errors) {
            if (error.Exception != null) {
                throw modelState.Errors[0].Exception;
            }
        }
    }

    Remove the comments surrounding the following line in the Products.ascx template to test the model state error debugging code.

    <%= Html.Hidden("ProductID", Model.ProductID)%>

    You get the following helpful message (at least for a developer) on where the problem occurred.

    The property 'ProductID' is part of the object's key information and cannot be modified.

    Posted by ricka0 | 0 Comments

    Setting font attributes with UIHint in your Entity Partial Class

     

    I've written a simple Field Template ( RedBold.ascx ) that reads most font attributes and applies them to your field values. The new entity templates make it easy to apply font attributes to the field labels. The image below shows several font attributes applied to the partial class for the Customer table of the AdventureWorksLT database.

    You can apply attributes (bold, italic, foreground color, background color, border style, border color, font name, etc) to the field name or the field value. For example, I specified the following attributes for the last name:

    [UIHint("RedBold", null, "Font-Size", "12", "Italic", "B",
            "Font_Name", "Comic Sans MS")]
    public object LastName { get; set; }
    

    The font size applies to both the label and the field value. For font attributes like bold and italic that are boolean, you can specify "F" to apply the attribute to the field, "L" to apply to the label or "B" to apply to both the field and label. When you specify an HTML font attribute, the attribute value applies to both the field value and the label. In the code sample above,  "Font_Name" , "Comic Sans MS" applies to both the field name and field value. To apply an attribute to a field value only, prepend the attribute name with "F_". To apply an attribute to a label only, prepend the attribute name with "L_".  The following code snippet shows the font attributes for the middle name and name style fields of the customer table.

    [UIHint("RedBold", null, "F_BorderStyle", "Dashed", "F_BorderWidth", "3",
            "F_BorderColor", "DeepPink", "L_BackColor", "Lime")]
    public object MiddleName { get; set; }

    [UIHint("RedBold", null, "L_BorderColor", "Magenta", "L_BorderStyle", "Groove", "L_BorderWidth", "4")] [Display(Name = "Name Style")] public object NameStyle { get; set; }

    Applying the font attributes to field values.

    I copied the Text.ascx field template to create RedBold.ascx and added the following PreRender method to apply the font hints. You don't even need the RedBold.ascx  field template, you could simply add the PreRender method and code below to the Text.ascx field template.

    protected override void OnPreRender(EventArgs e) {
        base.OnPreRender(e);
    
        UIHintAttribute hint = null;
        hint = (UIHintAttribute)this.Column.Attributes[typeof(UIHintAttribute)];
        if (hint == null ||
           hint.ControlParameters.Count < 1)
            return;
    
        FontHints.applyUIHints(hint, this.Literal1, /* isField */ true);
    }  

    Here is a portion of the appUIHints method.

    public static void applyUIHints(UIHintAttribute hint, Label lbl, bool isField) {
    
        if (hint.ControlParameters.ContainsKey("Font_Name")) {
            lbl.Font.Name = (string)hint.ControlParameters["Font_Name"];
        }
    
    }

    Entity Templates make it easy to apply font attributes to field labels.

    Add the lines after the comment // Add these lines  to the Label_Init method of the Default.ascx entity template.

    protected void Label_Init(object sender, EventArgs e) {
        Label label = (Label)sender;
        label.Text = currentColumn.DisplayName;
    
        // Add these lines for attribute applied font settings
        var hint = (UIHintAttribute)currentColumn.Attributes[typeof(UIHintAttribute)];
        if (hint == null ||
           hint.ControlParameters.Count < 1)
            return;
    
        FontHints.applyUIHints(hint, label, /*isField */ false);
    }

    Font attributes can be applied to any scaffolded table when displayed in the details view. The list.aspx page template does not use entity templates, so the font attributes will only apply to field values.

    Using font attributes with custom entity templates.

    My MSDN sample entity templates as written were unable to apply font attributes to the field labels, so I created a simple user control containing a literal (for the field label) and a DynamicControl (for the field value) to encapsulate the pair. The user control (Controls\Lbl_Literal_pair.ascx ) applies the font attributes from your partial class to your custom entity template. The following image shows the Address table from the AdventureWorksLT database using my custom entity template and several font attributes.

    AddressesET

    Some of the font attributes I apply include a border around the address field value, non-bold text for city, upper case for city (both the label and field value), lower case for state, italic text for the zip code label, and many more.

    Adding custom front attributes to your Dynamic Data project.

    You can download the complete project and copy FontHint.cs, Controls\Lbl_Literal_pair.ascx and DynamicData\FieldTemplates\RedBold.ascx to your project. You will have to change the namespace and annotate your entity partial class with [UIHint("RedBold" and font attributes. See partials.cs for examples. As mentioned previously, you don't even need to create the RedBold.ascx field template, you can apply my modifications to the default.ascx field template. Warning: The sample download requires Visual Studio 2010 Beta 1 or higher.

    Posted by ricka0 | 1 Comments
    Filed under:

    Attachment(s): FontAttrib.zip

    Dynamic Data FAQ

    Please post corrections/new submissions to the Dynamic Data Forum. Put FAQ Submission/Correction in your title.

    See Tips on getting your ASP.NET Dynamic Data questions answered quickly

    Post LINQ To SQL Questions here
    Post Entity Framework Questions here

    Links that will answer questions:

    From the Dynamic Data architect David Ebbo

    From http://blogs.msdn.com/rickAndy  (Most samples include VB)

    From ASP.Net Developer David Fowler 

    Q: How do I get started with Dynamic Data?
    A: If you like videos, see ASP.NET Dynamic Data videos
         MSDN on Dynamic Data
         Walkthrough: Creating a New ASP.NET Dynamic Data Web Site Using Scaffolding
         http://www.asp.net/dynamicdata/
         Dynamic Data Forum

    Q: What's new with Dynamic Data for .Net 4 Beta?  <-- New
    A: See this link.

    Q: The data annotation to my partial class is not working?
    A: The most common problem is no namespace or incorrect namespace around your partial class. A partial class that is not part of the data model (or part of another class) is known as a naked partial class. The easiest way to test if you have a naked partial class is to add a non-existing field to the partial class. In the following snippet,  bogus is not in the CustomerAddress table.

    [MetadataType(typeof(CustomerAddressMetaData))]
       public partial class CustomerAddress {
           public class CustomerAddressMetaData {
    
               [ScaffoldColumn(false)]
               public object ModifiedDate;
    
               public object bogus;
           }
       }

    When you run the Dynamic Data project, you will get the following exception in DefaultModel.RegisterContext (in global.asax):

    The associated metadata type for type 'DynamicDataProject.CustomerAddress' contains the following unknown properties or fields: bogus. Please make sure that the names of these members match the names of the properties on the main type.

    Q: How do I generate GUIDs on inserts?
    A: You don't, you shouldn't. Let the DB generate them or you will have performance problems. You can modify the data model XML and explicitly state they are DB generated. With the EDM, use StoreGeneratedPattern="Computed"  while Linq to SQL uses IsDbGenerated="true"

    Q: How to set Displayformat for a password field?
    A: See Steve's excellent Password FieldTemplates for Dynamic Data

    Q: How do I check for duplicates before I insert? (Or get values from the DB for any reason before I insert)
    A: see this post.

    Q: How do I mark a columns as read-only?
    A: see this post or Making a Field Read-Only via the ReadOnlyAttribute – Dynamic Data - Note the next version of Dynamic Data And The ASP.NET Dynamic Data 4.0 Preview 3 support the [ReadOnly(true)] attribute.

    Q: Can Dynamic Data use a data model generated by a 3rd party O/RM tool?
    A:The current Dynamic Data needs the following items to work with a technology:
    -    Technology must support Linq
    -    DataSource control must exist for the technology
    -    Dynamic Data ModelProvider must exist for the technology

    An example of one today is LLBLGen: http://www.llblgen.com/defaultgeneric.aspx

    nHibernate currently does not meet the Linq requirements.

    Q: What DB's are supported?
    A: See ADO.NET Entity Framework Providers

    Q: How do I hide columns from the Edit and other page templates?
    A: Suppose you want to display the Salary field, but you don't want to show it in the Edit and Insert templates. See Stephens popular tutorial

    Dynamic Data - Hiding Columns in selected PageTemplates

    Q: How do I disallow navigation links on Foreign Key columns?
    A: By default, DD displays the first string column in the Foreign Key table in stead of the FK. This is rendered as a link (NavigateUrl) to the FK table. If you're not happy with the default (column shown) use the DisplayColumn attribute on the FK table to specify which property is displayed. See also Improving the FK field display: Showing two fields in Foreign Key columns. Back to the original question. The easiest way to disable the FK property from being a NavigateUrl is to hide the FK table by annotating your entity partial class with the ScaffoldTable   attribute. Note,  ScaffoldTable   will hide your table. If you want to expose your table but disable the hyperlink - see Stephens excellent blog Allow Navigation on ForeignKey FieldTemplate – Dynamic Data

    Q: How do I move the Edit Delete Details links from the left side (column 0) to the right side of the table.
    A: Create your own IAutoFieldGenerator.GenerateFields and add the command field at the end. (thx David Fowler). See this post.

    Q: How do I implement role based security? (tables/columns visibility dependent on users role).
    A: See this post, and custom IAutoFieldGenerator

    Q: How do map stored procedures (sprocs) to Inserts and get back the auto generated PK using L2S?
    A: See LINQ to SQL (Part 7 - Updating our Database using Stored Procedures) , Stored Procedures (LINQ to SQL) and How to override default insert method of Details View in Dynamic Data .

    Posted by ricka0 | 1 Comments
    Filed under:

    Custom Validation Error message not displayed

     

    A customer pointed out that his Spanish validation error messages were not being displayed; the default Error message was shown instead.  I'll use the Products table from the NorthWind Db to reproduce the problem and show a work-around.

    Create a partial class for the Products entity:

     [MetadataType(typeof(ProductsMD))]
        public partial class Products {
            public class ProductsMD {
                [DataType("dummy", ErrorMessage = "El campo debe ser un entero positivo")]
                [DisplayName("En la acción")]
                public object UnitsInStock { get; set; }
            }
        }
    VB
        <MetadataType(GetType(ProductsMD))> _
    Public Class Products
            Public Class ProductsMD
                <DataType("dummy", ErrorMessage:="El campo debe ser un entero positivo"), _
                 DisplayName("En la acción")> _
                Public Property UnitsInStock() As Object
                End Property
            End Class
        End Class

    Navigate to the Products table, edit a row, and change the UnitsInStock to a letter. Select update and you will get a default error message, not the message applied with the DataType attribute.

    The example above was doomed to failure as the DataType attribute above does not match the DataType enum or have a matching field template.

    There are a couple of possible solutions for displaying custom validation errors on integer conversion failure. You can add the compare validator message that will be displayed for any validation error. The code should be added as the last statement of the Page_Load method in the DynamicData\FieldTemplates\Integer_Edit.ascx.cs  (or .vb) file.

    CompareValidator1.ErrorMessage = String.Format("El campo {0} debe ser un entero", Column.DisplayName);

    or for VB

    CompareValidator1.ErrorMessage = String.Format("El campo {0} debe ser un entero", Column.DisplayName)

    Entering a non-integer such as Z to the units in stock field now yields the following error message:

    El campo En la acción debe ser un entero

    Adding the CompareValidator1.ErrorMessage to the integer template works for every scaffolded integer.

    For more flexibility, you can extract the custom message from the data model partial class. Replace the CompareValidator1.ErrorMessage  line above with the following in the Page_Load method.

     var dataTypeAttribute = MetadataAttributes.OfType<DataTypeAttribute>().SingleOrDefault();
    
     if (dataTypeAttribute != null) {
        CompareValidator1.ErrorMessage = dataTypeAttribute.FormatErrorMessage(Column.DisplayName);
     }

    VB

    Dim dataTypeAttribute = MetadataAttributes.OfType(Of DataTypeAttribute)().SingleOrDefault() 
    
    If dataTypeAttribute IsNot Nothing Then 
        CompareValidator1.ErrorMessage = dataTypeAttribute.FormatErrorMessage(Column.DisplayName) 
    End If 

    Even simpler than adding a dummy attribute and extracting the error message;  use the RegularExpression attribute and allow only positive integers. The following snippet fixes the error message problem without requiring you to extract the error message in the Page_Load method.

      [MetadataType(typeof(ProductsMD))]
        public partial class Products {
            public class ProductsMD {
      //          [DataType("dummy", ErrorMessage = "El campo debe ser un entero positivo")]
                [RegularExpression(@"^0*[1-9][0-9]*$", ErrorMessage = "Must be a entero positivo")]
                [DisplayName("En la acción")]
                public object UnitsInStock { get; set; }
            }
        }
    VB
    <MetadataType(GetType(ProductsMD))> _ 
    Public Partial Class Products 
        Public Class ProductsMD 
    Private _UnitsInStock As Object 
            ' [DataType("dummy", ErrorMessage = "El campo debe ser un entero positivo")] 
            <RegularExpression("^0*[1-9][0-9]*$", ErrorMessage := "Must be a entero positivo")> _ 
            <DisplayName("En la acción")> _ 
            Public Property UnitsInStock() As Object 
                Get 
                    Return _UnitsInStock 
                End Get 
                Set(ByVal value As Object) 
                    _UnitsInStock = value 
                End Set 
            End Property 
        End Class 
    End Class 

    Notes:

    1. We are using the DataType attribute as a dummy attribute so we can extract our custom error message when a validation error occurs.
    2. This is a known bug that should be fixed in the next release.
    Posted by ricka0 | 3 Comments
    Filed under: ,

    Explicit connection string for EF

    The default constructor for the ObjectContext class in the  Entity Data Model (EDM) retrieves the construction string from the web.config or app.config file. If you have multiple data models or need to pass in the the construction string at run time you must use the ObjectContext constructor that takes a construction string. (Note: Be sure to see the bug/work-around at the end of this article.) The follow snippet shows how to build the string for integrated security.

    //  copy connection string from app.config or web.config  
    
        // connectionString="metadata=res://*;
        // provider=System.Data.SqlClient;
        // provider connection string=&quot;
        // Data Source=ricka0;Initial Catalog=Northwind;Persist Security Info=True;
        // User ID=sa;Password=*(IU89iu;MultipleActiveResultSets=True&quot;"
        // providerName="System.Data.EntityClient" 
        
    
        public static string UglyConStr() {
    
            return "metadata=res://*;"
              + "provider=System.Data.SqlClient;"
              + "provider connection string=';"  // Replace &quot with ' (single quote)
            + "Data Source=ricka0;"
            + "Initial Catalog=Northwind;"
            + "Persist Security Info=True;"
            + "User ID=sa;Password=*(IU89iu;"
            + "MultipleActiveResultSets=True';"  // Replace &quot with ' (single quote)
                //    + "providerName=\"System.Data.EntityClient\""
            ;
        }

    While the construction string above works, it's very ugly. The hair pulling trick to get it working is replacing &quot with a single quote ' as shown in the comments. Using  the raw connection string from the config file (using &quot ) results in a misleading error message Keyword not supported: 'data source'.  

    A much more elegant construction string using SQL connection is shown below.

     public static string getConStrSQL() {
    
            string connectionString = new System.Data.EntityClient.EntityConnectionStringBuilder
            {
                Metadata = "res://*",
                Provider = "System.Data.SqlClient",
                ProviderConnectionString = new System.Data.SqlClient.SqlConnectionStringBuilder
                {
                    InitialCatalog = "Northwind",
                    DataSource = "ricka0",
                    IntegratedSecurity = false,
                    UserID = getUID(),                 // User ID such as "sa"
                    Password = getPWD(),               // hide the password
                }.ConnectionString
            }.ConnectionString;
    
            return connectionString;
        }

    In VB:

    Public Shared Function getConStrSQL() As String
         Dim connectionString As String = New System.Data.EntityClient.EntityConnectionStringBuilder() _
             With {.Metadata = "res://*", _
                   .Provider = "System.Data.SqlClient", _
                   .ProviderConnectionString = New System.Data.SqlClient.SqlConnectionStringBuilder() _
                     With {.InitialCatalog = "Northwind", _
                           .DataSource = "ricka0", _
                           .IntegratedSecurity = False, _
                           .UserID = getUID(), _
                           .Password = getPWD()}.ConnectionString}.ConnectionString
         Return connectionString
     End Function

    The integrated security approach is slightly different.

    public static string getConStrIntegrated() {
    
            string conStrIntegratedSecurity = new System.Data.EntityClient.EntityConnectionStringBuilder
               {
                   Metadata = "res://*",
                   Provider = "System.Data.SqlClient",
                   ProviderConnectionString = new System.Data.SqlClient.SqlConnectionStringBuilder
                   {
                       InitialCatalog = "NorthwindEF",
                       DataSource = "bing0",
                       IntegratedSecurity = true,
                   }.ConnectionString
               }.ConnectionString;
    
            return conStrIntegratedSecurity;
        }
    For Dynamic Data, simply pass the construction string to the MetaModel RegisterContext as follows. 
     public static void RegisterRoutes(RouteCollection routes) {
            MetaModel model = new MetaModel();
    
    
            model.RegisterContext(() => new NorthwindModel.NorthwindEntities(getConStrIntegrated()),
                new ContextConfiguration()
                {
                    ScaffoldAllTables = true
                });
    
            // Routes omitted for clarity
        }

    Unfortunately, the current version of Dynamic Data doesn't support this approach with EF (L2S does work). To get the page templates to use the connection string you must add the following line to the Page_Load method in the page templates.

    GridDataSource.ContextCreating += delegate(object ceSender, System.Web.UI.WebControls.EntityDataSourceContextCreatingEventArgs ceArgs) {
                ceArgs.Context = (System.Data.Objects.ObjectContext)table.CreateContext();
            };

    The complete Page_Load is below

    protected void Page_Load(object sender, EventArgs e) {
            table = GridDataSource.GetTable();
    
             GridDataSource.ContextCreating += delegate(object ceSender, System.Web.UI.WebControls.EntityDataSourceContextCreatingEventArgs ceArgs) {
                ceArgs.Context = (System.Data.Objects.ObjectContext)table.CreateContext();
            }; 
    
            Title = table.DisplayName;
            GridDataSource.Include = table.ForeignKeyColumnsNames;
            InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert);
    
            // Disable various options if the table is readonly
            if (table.IsReadOnly) {
                GridView1.Columns[0].Visible = false;
                InsertHyperLink.Visible = false;
            }
        }
    Posted by ricka0 | 2 Comments

    Improving the FK field display: Showing two fields in Foreign Key columns

     

    The default scaffold of the CustomerAddress table in the AdventureWorksLT database poses a problem: Dynamic Data (DD) defaults to using the first string field in the referenced table. In this case, the first string field is the Title field (Mr,Ms, and so on).  The image below shows the problem with the FilterRepeater drop down list and Customer column elements.

    We can take a first step toward fixing this issue by creating and annotating a partial class for the Customer entity. The code below now displays the LastName field for the customer entity. The DisplayColumn attribute tells referring entities which column to use for display instead of the Foreign Key field.

     [DisplayColumn("LastName")]
     [MetadataType(typeof(CustomerMetaData))]
     public partial class Customer {
          public class CustomerMetaData {
       }
     }

    While the resulting view is an improvement, it’s not there yet. Note that it doesn't distinguish between the customers with non-unique last names, such as Adams or Liu.

     

    To fix this, we overload the ToString method for the Customer partial class as shown below:

    // [DisplayColumn("LastName")]
    [MetadataType(typeof(CustomerMetaData))]
    public partial class Customer {
    
         public override string ToString() {
             return LastName.ToString() + ", " + FirstName.ToString();
         }
    
         public class CustomerMetaData {
    
    }

    The resulting display gets it right: the code now shows the correct field, and it distinguishes between David, Jinghao and Kevin Liu.

    Special thanks to David Ebbo for recommending the ToString() approach and Phil Haack for granting me blog dibs.

    Posted by ricka0 | 6 Comments
    Filed under: ,

    How to create an updateable view with ADO Entity Framework and with LINQ to SQL

    Creating an update-able view with  ADO Entity Framework (EF) or LINQ to SQL (L2S) is a fairly advanced topic and not directly associated with Dynamic Data. At the end of the article I have a sample console application to verify the modified L2S data model allows updates on a view. To create an update-able view, you must modify the wizard (or other tool) generated XML file (data model). Each time you generate a new data model (for example when the schema changes), you will need to reapply these steps.

    ADO Entity Framework (EF) makes views Read Only via the <DefiningQuery> element. You make the data model view update-able by removing the <DefiningQuery> element and making a few minor changes. Note the example below is a very simple view on one table and includes the primary key.

    This is what I did to make an update-able view for the AdventureWorksLT DB

    CREATE VIEW [SalesLT].[vAddr]
    AS
    SELECT
    AddressID,[AddressLine1],[City],[StateProvince],[CountryRegion],[PostalCode]
    FROM [AdventureWorksLT2008].[SalesLT].[Address]

    The next line shows this view is update-able (at least from T-SQL)  

    UPDATE vAddr SET PostalCode = '54321'
    WHERE addressID > 11382 AND
    StateProvince
    = 'WA'

     (18 row(s) affected) 

    Edit the EF SSDL, comment out the <DefiningQuery> , remove store: prefix from Schema="SalesLT"  and remove store:Name="vAddr" . The commented/changed code below

    <EntitySet Name="Address" EntityType="AdventureWorksLT2008Model.Store.Address" store:Type="Tables" Schema="SalesLT" />
    <
    EntitySet Name="vAddr" EntityType="AdventureWorksLT2008Model.Store.vAddr" store:Type="Views" Schema="SalesLT" />

    <!--<EntitySet Name="vAddr" EntityType="AdventureWorksLT2008Model.Store.vAddr" store:Type="Views" store:Schema="SalesLT" store:Name="vAddr"> -->
    <!--
    <DefiningQuery>SELECT [vAddr].[AddressID] AS [AddressID], [vAddr].[AddressLine1] AS [AddressLine1], [vAddr].[City] AS [City],
    [vAddr].[StateProvince] AS [StateProvince],
    [vAddr].[CountryRegion] AS [CountryRegion],
    [vAddr].[PostalCode] AS [PostalCode]
    FROM [SalesLT].[vAddr] AS [vAddr]</DefiningQuery>
    -->
    <!--
    </EntitySet>-->

    </EntityContainer>

    LINQ to SQL is the simplest.

    Using the view above,

    Simply change the following line in the wizard generated code to use    AutoSync = AutoSync.OnInsert in lieu of AutoSync=AutoSync.Always on the AddressID property.

    // [Column(Storage="_AddressID", AutoSync=AutoSync.Always, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
    [Column(Storage =
    "_AddressID", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
    public int AddressID

    The following example shows how to test the view from a console application.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Linq;
    using System.Data.Linq.Mapping;
    
    namespace updateableView {
    
            public class T {
                public LTDataContext db;
                //    readonly string con = "Data Source=bing0;Initial Catalog=AdventureWorksLT2008;Integrated Security=True";
                readonly string con = "Data Source=bing0;Initial Catalog=AdventureWorksLT2008;" +
                                       "Persist Security Info=True;User ID=sa;Password=*(IU89iu";
    
                public T() {
                    db = new LTDataContext(con);
                }
    
                public void addAddr(string city) {
    
                    vAddr adr = new vAddr();
                    adr.AddressLine1 = "1234 N St.";
                    adr.City = city;
                    adr.PostalCode = "99966";
                    adr.StateProvince = "Mt";
                    adr.CountryRegion = "None";
    
                    db.vAddrs.InsertOnSubmit(adr);
                    db.SubmitChanges();
                }
    
                public void tq(string city) {
    
                    Table<vAddr> addr = db.GetTable<vAddr>();
                    var q = from c in addr
                            where c.City == city
                            select c;
    
                    foreach (var cst in q)
                        Console.WriteLine("id = {0}, City = {1}", cst.AddressID, cst.City);
                }
            }
    
            class Program {
                static void Main(string[] args) {
                    T tdb = new T();
                    string city = "GF";
                    tdb.addAddr(city);
                    tdb.tq(city);
    
                }
            }
        }
    
    
    Posted by ricka0 | 3 Comments
    Filed under: ,

    Tweaking the Filter Repeater

    The default implementation of Dynamic Data provides a drop down list box for each foreign key and boolean field in a table. The drop down list allows you to filter the table with the value selected from the drop down list box. The figure below shows a view of the Product table from the AdventureWorksLT database. Several columns are not displayed because the scaffoldcolumnattribute was applied.

    The figure below shows the Product table again after Mountain Bikes is selected in the ProductCategory drop down list. Only products with product category Mountain Bikes are displayed.

    The drop down list box is implemented in Dynamic Data by the FilterUserControl.ascx user control in the DynamicData\Content folder. While the filter user control is useful to filter a table when there are a relatively few foreign keys used as categories, it can be unmanageable on tables with hundreds or more foreign keys. For example, the CustomerAddress table of the AdventureWorksLT database has over 400 AddressID foreign keys, and each foreign key points to only one address of a customer (either the Main Office or the Shipping address).

    When the foreign key field displayed by the filter user control is a very long string, the drop down list box can move off the browser window. This document will offer and approach to limit the width of the drop down list box. The figure below shows the ProductModelProductDescriptions from the AdventureWorksLT database.

    In this blog I show how I like to establish a maximum number of entries in the filter repeater and how to set the maximum width.

    Modifying the filter user control to limit number of entries

    Editing the filter user control

    1. Add a key element to the appSettings Element in the web.config file that will set an upper bound to the number of foreign key entries that will be displayed. The following example sets the upper bound to 55. 

    <appSettings>
      <add key="FilterUC_FK_limit" value="955"/>
      <add key="FilterUC_Char_limit" value="50"/>
    </appSettings>

    1 Add a text label to the the filter user control in the FilterUserControl.ascx file found in the DynamicData\Content folder. The following example shows the completed markup.

    <%@ Control Language="C#" CodeFile="FilterUserControl.ascx.cs" Inherits="FilterUserControl" %>
    
    <asp:Label ID="LBL1" runat="server" Text="Label" ForeColor= "Brown" Font-Bold="true" />
    <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" EnableViewState="true" CssClass="droplist">
        <asp:ListItem Text="All" Value="" />
    </asp:DropDownList>
    

    3. Add a string property to the FilterUserControl. For example, add a property with the name LBL_Txt that will be used to set the label we added to the FilterUserControl.aspx file in a previous step.

    4. Add the Page_PreRender method in the FilterUserControl code behind file and set the label text. For example, set the label text with the LBL_Txt property created in the previous step.

    5. Modify the Page_Init method in the FilterUserControl code behind file to limit the number of foreign keys displayed. The FilterUC_FK_limit application setting created in the first step will be used to set the maximum number of entries in the drop down list box. The following example shows the completed FilterUserControl code behind file.

    Visual Basic

    Imports System.Web.DynamicData
    
    Partial Class FilterUserControl
        Inherits System.Web.DynamicData.FilterUserControlBase
        '
        Public LBL_Txt As String
        '
        Public Overrides ReadOnly Property SelectedValue As String
            Get
                Return DropDownList1.SelectedValue
            End Get
        End Property
        '
        Public Event SelectedIndexChanged As EventHandler
        '
        Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
            '
            If Page.IsPostBack Then
                Return
            End If
            '
            PopulateListControl(DropDownList1)
            '
            Dim maxCnt As Integer = Convert.ToInt32(ConfigurationManager.AppSettings("FilterUC_FK_limit"))
            If (DropDownList1.Items.Count > maxCnt) Then
                DropDownList1.Visible = False
                LBL1.Visible = False
            End If
            '
            If Not String.IsNullOrEmpty(InitialValue) Then
                DropDownList1.SelectedValue = InitialValue
            End If
            '
        End Sub
        '
        '
        Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
            LBL1.Text = LBL_Txt
        End Sub
    End Class
    

    C#

    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Xml.Linq;
    using System.Web.DynamicData;
    
    public partial class FilterUserControl : System.Web.DynamicData.FilterUserControlBase {
    
        public string LBL_Txt { get; set; }
    
        public event EventHandler SelectedIndexChanged {
            add {
                DropDownList1.SelectedIndexChanged += value;
            }
            remove {
                DropDownList1.SelectedIndexChanged -= value;
            }
        }
    
        public override string SelectedValue {
            get {
                return DropDownList1.SelectedValue;
            }
        }
    
        protected void Page_PreRender(object sender, EventArgs e) {
            LBL1.Text = LBL_Txt;
        }
    
        protected void Page_Init(object sender, EventArgs e) {
    
            if (Page.IsPostBack)
                return; PopulateListControl(DropDownList1);
    
            int maxCnt = Convert.ToInt32(ConfigurationManager.AppSettings["FilterUC_FK_limit"]); 
            if (DropDownList1.Items.Count > maxCnt) {
                DropDownList1.Visible = false;
                LBL1.Visible = false;
            }
    
            if (!String.IsNullOrEmpty(InitialValue))
                DropDownList1.SelectedValue = InitialValue;
        }
    }


     

    5. Remove the original filter label from the page template (list.aspx and listDetails.aspx) and initialize the new label. The original markup is shown below.

    <asp:FilterRepeater ID="FilterRepeater" runat="server">
        <ItemTemplate>
           <asp:Label runat="server" Text='<%# Eval("DisplayName") %>' AssociatedControlID="DynamicFilter$DropDownList1" />
            <asp:DynamicFilter runat="server" ID="DynamicFilter" OnSelectedIndexChanged="OnFilterSelectedIndexChanged" />
         </ItemTemplate>
         <FooterTemplate><br /><br /></FooterTemplate>
     </asp:FilterRepeater>

    The replacement markup is shown below.

    <ItemTemplate>
        <asp:DynamicFilter runat="server" ID="DynamicFilter" LBL_Txt='<%# Eval("DisplayName") %>'
                          OnSelectedIndexChanged="OnFilterSelectedIndexChanged" />
      </ItemTemplate>

     

    Part II:  Limiting the width of the filter user control Part II:

    To limit the width of the drop down list box, the elements of the list box will be truncated at the maximum allowed character width.Editing the filter user control for maximum characters1. Add a key element to the appSettings Element in the web.config file that will set an upper bound on the number of characters that will be copied to each element of the drop downn list. The key with value FilterUC_Char_limit sets the maximum number of characters to 50.

    <appSettings>
      <add key="FilterUC_FK_limit" value="955"/>
      <add key="FilterUC_Char_limit" value="50"/>
    </appSettings>

    2. Modify the Page_Init method in the FilterUserControl code behind file to limit the number of characters to be copied to the drop down list box. The following example shows how to limit the number of characters.

    C#

    int maxLen = Convert.ToInt32(ConfigurationManager.AppSettings["FilterUC_Char_limit"]);
    
    for (int i = 0; i < DropDownList1.Items.Count; i++) {
       string s = DropDownList1.Items[i].Text;
    
       if (s.Length > maxLen) {
          s = s.Substring(0, maxLen - 1);
          s += " ... (see Details for full)";
          DropDownList1.Items[i].Text = s;
       }
    }

    Visual Basic

    Dim maxLen As Integer = Convert.ToInt32(ConfigurationManager.AppSettings("FilterUC_Char_limit"))
       For i As Integer = 0 To DropDownList1.Items.Count - 1
    
           Dim s As String = DropDownList1.Items(i).Text
    
           If s.Length > maxLen Then
               s = s.Substring(0, maxLen - 1)
               s += " ... (see Details for full)"
               DropDownList1.Items(i).Text = s
           End If
       Next

    The figure below shows the results with the ProductModelProductDescription table.

    Posted by ricka0 | 3 Comments
    Filed under: ,
     
    Page view tracker