Top asp.net-mvc Questions

List of Tags
663
Mark Struzinski

I'm taking my first crack at Ajax with jQuery. I'm getting my data onto my page, but I'm having some trouble with the JSON data that is returned for Date data types. Basically, I'm getting a string back that looks like this:

/Date(1224043200000)/

From someone totally new to JSON - How do I format this to a short date format? Should this be handled somewhere in the jQuery code? I've tried the jQuery.UI.datepicker plugin using $.datepicker.formatDate() without any success.

FYI: Here's the solution I came up with using a combination of the answers here:

function getMismatch(id) {
  $.getJSON("Main.aspx?Callback=GetMismatch", 
    { MismatchId: id },

    function (result) {
      $("#AuthMerchId").text(result.AuthorizationMerchantId);
      $("#SttlMerchId").text(result.SettlementMerchantId);
      $("#CreateDate").text(formatJSONDate(Date(result.AppendDts)));
      $("#ExpireDate").text(formatJSONDate(Date(result.ExpiresDts)));
      $("#LastUpdate").text(formatJSONDate(Date(result.LastUpdateDts)));
      $("#LastUpdatedBy").text(result.LastUpdateNt);
      $("#ProcessIn").text(result.ProcessIn);
    }
  );

  return false;
}

function formatJSONDate(jsonDate) {
  var newDate = dateFormat(jsonDate, "mm/dd/yyyy");
  return newDate;
}

This solution got my object from the callback method and displayed the dates on the page properly using the date format library.

Answered By: Roy Tinker ( 688)

Eval is not necessary. This will work fine:

var date = new Date(parseInt(jsonDate.substr(6)));

The substr function takes out the "\/Date(" part, and the parseInt function gets the integer and ignores the ")\/" at the end. The resulting number is passed into the Date constructor.

Everytime a user posts something containing < or > in a page in my webapp, I get this exception thrown.

I don't want to go into the discussion about the smartness of throwing an exception or crashing an entire webapp because somebody entered a character in a textbox, but I am looking for an elegant way to handle this.

Trapping the exception and showing "An error has occured please go back and re-type your entire form again, but this time please do not use <" doesn't seem professional enough to me

Disabling post validation ( validateRequest="false" ) will definitelly avoid this error, but it will leave the page vulnerable to a number of attacks.

Ideally: when a postback occurs containing HTML restricted caracters, that posted value in the Form collection will be automatically HTML encoded. So the .Text property of my text-box will be " something & lt; html & gt; "

Any way I can do this from a handler?

Answered By: JacquesB ( 365)

I think you are attacking it from the wrong angle by trying to encode all posted data.

Note that a "<" could also come from other outside sources, like a database field, a configuration, a file, a feed and so on.

Furthermore, "<" is not inherently dangerous, its only dangerous in a specific context: when writing unencoded strings to HTML output (because of XSS). In other contexts different substrings are dangerous, e.g. if you write an user-provided URL into a link, the substring "javascript:" may be dangerous. The single quote character on the other hand is dangerous when interpolating strings in SQL queries, but perfectly safe if it is a part of a name submitted from a form or read from a database field.

The bottom line is: you can't filter random input for dangerous characters, because any charater may be dangerous under the right circumstances. You should encode at the point where some specific characters may become dangerous because they cross into a different sublanguage where they have special meaning. When you write a string to HTML, you should encode characters that have special meaning in HTML, using Server.HtmlEncode. If you pass a string to a dyamic SQL statement, you should encode different characters (or better, let the framework do it for you by using prepared statements or the like).

When you are sure you HTML-encode everywhere you pass strings to HTML, then set validateRequest="false".

In .NET 4 you may need to do a little more. Sometimes it's necessary to also add <httpRuntime requestValidationMode="2.0" /> to web.config (reference).

344
dswatik

I am trying to use ELMAH to log errors in my ASP.NET MVC application, however when I use the [HandleError] attribute on my controllers ELMAH doesn't log any errors when they occur.

As I am guessing its because ELMAH only logs unhandled errors and the [HandleError] attribute is handling the error so thus no need to log it.

How do I modify or how would I go about modifying the attribute so ELMAH can know that there was an error and log it..

Edit: Let me make sure everyone understands, I know I can modify the attribute thats not the question I'm asking... ELMAH gets bypassed when using the handleerror attribute meaning it won't see that there was an error because it was handled already by the attribute... What I am asking is there a way to make ELMAH see the error and log it even though the attribute handled it...I searched around and don't see any methods to call to force it to log the error....

Answered By: Atif Aziz ( 343)

You can subclass HandleErrorAttribute and override its OnException member (no need to copy) so that it logs the exception with ELMAH and only if the base implementation handles it. The minimal amount of code you need is as follows:

using System.Web.Mvc;
using Elmah;

public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        base.OnException(context);
        if (!context.ExceptionHandled) 
            return;
        var httpContext = context.HttpContext.ApplicationInstance.Context;
        var signal = ErrorSignal.FromContext(httpContext);
        signal.Raise(context.Exception, httpContext);
    }
}

The base implementation is invoked first, giving it a chance to mark the exception as being handled. Only then is the exception signaled. The above code is simple and may cause issues if used in an environment where the HttpContext may not be available, such as testing. As a result, you will want code that is that is more defensive (at the cost of being slightly longer):

using System.Web;
using System.Web.Mvc;
using Elmah;

public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        base.OnException(context);
        if (!context.ExceptionHandled       // if unhandled, will be logged anyhow
            || TryRaiseErrorSignal(context) // prefer signaling, if possible
            || IsFiltered(context))         // filtered?
            return;

        LogException(context);
    }

    private static bool TryRaiseErrorSignal(ExceptionContext context)
    {
        var httpContext = GetHttpContextImpl(context.HttpContext);
        if (httpContext == null)
            return false;
        var signal = ErrorSignal.FromContext(httpContext);
        if (signal == null)
            return false;
        signal.Raise(context.Exception, httpContext);
        return true;
    }

    private static bool IsFiltered(ExceptionContext context)
    {
        var config = context.HttpContext.GetSection("elmah/errorFilter")
                        as ErrorFilterConfiguration;

        if (config == null)
            return false;

        var testContext = new ErrorFilterModule.AssertionHelperContext(
                              context.Exception, 
                              GetHttpContextImpl(context.HttpContext));
        return config.Assertion.Test(testContext);
    }

    private static void LogException(ExceptionContext context)
    {
        var httpContext = GetHttpContextImpl(context.HttpContext);
        var error = new Error(context.Exception, httpContext);
        ErrorLog.GetDefault(httpContext).Log(error);
    }

    private static HttpContext GetHttpContextImpl(HttpContextBase context)
    {
        return context.ApplicationInstance.Context;
    }
}

This second version will try to use error signaling from ELMAH first, which involves the fully configured pipeline like logging, mailing, filtering and what have you. Failing that, it attempts to see whether the error should be filtered. If not, the error is simply logged. This implementation does not handle mail notifications. If the exception can be signaled then a mail will be sent if configured to do so.

You may also have to take care that if multiple HandleErrorAttribute instances are in effect then duplicate logging does not occur, but the above two examples should get your started.

253
Daniel Magliola

I've heard Jeff Atwood, Joel Spolsky, and many other legendary people talk about how the ASP.NET Web Forms model sucks (so this question is kind of directed to them, hopefully Jeff is reading).

Now, I highly respect their opinion, given their background and expertise, but truth be told, I absolutely LOVE Web Forms. I think the model is brilliant, and it sucks if you have no idea what you're doing, but once you understand how to control ViewState, when to use handlers instead of pages, etc, it is generations ahead of all the other models.

So every time I hear someone complain about how it sucks, I can't help ask the same question...
Why? What is it that's so bad about it?

I appreciate all opinions. I'm assuming there's probably a post at Jeff's blog talking about this too...

Answered By: Winston Fassett ( 190)

I'm glad we're talking about this.

It's not so much the model / philosophy of WebForms (being component-oriented, that is) that sucks as it is the implementation. And even that bit is not all bad.

While WebForms definitely merits criticism, I think it's incorrect to jump to the conclusion that MVC is a better / more virtuous concept. It's not. It depends on what you are trying to do.

Regarding the "patterns"

I'm not sure if the WebForms "pattern" has an official name, but let's call it a component framework. There are others, like JSF, which is a bit newer, and could perhaps teach us a few things. Contrast this with MVC, which is not component-oriented. Some people are opposed to componentization. For example, DHH in the rails community (the source of all the recent MVC hooplah), rants against components. However, his justification is more of an appeal to people to re-invent/re-work the wheel every time, because his goal is to make development "so very easy that you will treasure the application-specific solutions of your own rather than long for [components]". It is possible to hack up primitive reusable "components" in MVC. However, the more sophisticated and reusable you make your component, the more hackery you will have to do, because the goal of MVC is simplicity and separation, rather than composition / componentization.

Good Things about WebForms

  • You can compose very sophisticated, nicely encapsulated "controls" that can manage their own state, behavior, and rendering, and combine them into more sophisticated controls
    • Through them, you can accomplish a lot simply through declarative (.aspx) code.
    • For example, you can easily add a date picker that provides both client and server side validation because it has its own lifecycle.
    • Things like GridViews and DataSources - with robust editing, paging, sorting, and filtering capabilities, for example, are a very useful mechanism that couldn't be fully implemented outside of a component-oriented framework.
  • This is largely due to:
    • The component tree and naming containers
    • The page lifecycle - Page_Load, Page_PreRender, etc. enable several hooks that allow the entire view to be composed in one pass, but also modified before rendering in another pass (which is very useful if you are doing anything modular at all)
  • Mechanisms for tracking state (very useful when you need them):
    • ViewState
    • PostBacks (LinkButtons, etc)

Bad Things about WebForms

Again, most of these have to do with how WebForms is implemented.

  • The page / control lifecycle is complex.
  • ViewState is poorly implemented by the components, i.e. the convention of storing every property in ViewState, or that DropDownList doesn't work with ViewState disabled
  • There is no alternative to postbacks. Doing GET / QueryString-based forms is painful. And you can't have more than one <form runat="server">
  • There is no way to override the naming container strategy, which means ugly names for HTML elements
  • WebForms is stale and hasn't gotten many improvements. Probably due to concerns about compatibility, several new controls have been added, but the underlying architecture / mindset hasn't changed much.
  • Much of the framework and controls are mysterious and poorly documented. Plus it's closed source and that means that unless we want to live in Reflector, we are largely stuck with what we get.
  • Binding is horrible. The reflection breaks occasionally, Two-way binding is hard to use and unintuitive. There is no declarative way to bind to the QueryString. So we often spend a lot of time writing mindless binding/plumbing code. (I truly believe that a big reason people like MVC, and why people liked Struts and Rails for that matter, is because they handle binding well.)
  • WebForms is full of tight coupling that makes automated testing very difficult.

Clarifications

  • Regarding the URL-rewriting point, that's just not true. We are doing URL rewriting with WebForms. The .aspx extension is avoidable.
  • That the protocol is stateless is a moot point. It underscores the fact that we have to figure out how to manage state in our applications, and sometimes things like ViewState or PostBacks are the best solution. The flaw in the WebForms mindset is in assuming they are.
  • Partial PostBacks are much lighter weight than full PostBacks. Only need the properties of a Gridview and Filter Panel? Wrap them in an Update Panel. Much of the argument against PostBacks disappears when Partial Postbacks enter the conversation.

I'm hesitant to throw out the baby with the bath-water. We used WebForms for our social media site. We did a PoC in ASP.NET MVC as well, and found that it made a lot more sense to build robust, composable controls that could easily be moved from page to page, than to grapple with the limitations imposed by MVC's simplicity (and, in the case of the ASP.NET MVC framework, immaturity). I would much rather see MS overhaul WebForms, clarify the pros/cons with MVC, open up much of the source, and have the dev community support it as we have the MVC stuff, than for it to continue to be shunned (and neglected) as all of us jump onto the MVC bandwagon.

248
Remus Rusanu

I am looking at the MvcContrib Grid component and I'm fascinated, yet at the same time repulsed, by a syntactic trick used in the Grid syntax:

.Attributes(style => "width:100%")

The syntax above sets the style attribute of the generated HTML to width:100%. Now if you pay attention, 'style' is nowhere specified, is deduced from the name of the parameter in the expression! I had to dig into this and found where the 'magic' happens:

   Hash(params Func<object, TValue>[] hash)
   {
     foreach (var func in hash)
     {
       Add(func.Method.GetParameters()[0].Name, func(null));
     }
   }

So indeed, the code is using the formal, compile time, name of parameters to create the dictionary of attribute name-value pairs. The resulted syntax construct is very expressive indeed, but at the same time very dangerous. The general use of lambda expressions allows for replacement of the names used without side effect. I see an example in a book that says collection.ForEach(book => Fire.Burn(book)) I know I can write in my code collection.ForEach(log => Fire.Burn(log)) and it means the same thing. But with the MvcContrib Grid syntax here all of the sudden I find code that actively looks and makes decissions based on the names I choose for my variables!

So is this common practice with the C# 3.5/4.0 community and the lambda expressions lovers? Or is a rogue one trick maverick I shouldn't worry about?

Answered By: Brian ( 89)

This has poor interop. For example, consider this C# - F# example

C#:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

F#:

Class1.Foo(fun yadda -> "hello")

Result:

"arg" is printed (not "yadda").

As a result, library designers should either avoid these kinds of 'abuses', or else at least provide a 'standard' overload (e.g. that takes the string name as an extra parameter) if they want to have good interop across .Net languages.

216
John Oxley

I want an msbuild task to compile the views so I can see if there are compile time errors at well... compile time. Any ideas?

Answered By: JarrettV ( 246)

From the readme word doc for RC1 (not indexed by google)

ASP.NET Compiler Post-Build Step

Currently, errors within a view file are not detected until run time. To let you detect these errors at compile time, ASP.NET MVC projects now include an MvcBuildViews property, which is disabled by default. To enable this property, open the project file and set the MvcBuildViews property to true, as shown in the following example:

<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
  </PropertyGroup>

Note Enabling this feature adds some overhead to the build time.

You can update projects that were created with previous releases of MVC to include build-time validation of views by performing the following steps:

  1. Open the project file in a text editor.
  2. Add the following element under the top-most <PropertyGroup> element: <MvcBuildViews>true</MvcBuildViews>
  3. At the end of the project file, uncomment the <Target Name="AfterBuild"> element and modify it to match the following:
<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
</Target>
213
Ghooti Farangi

What is difference between Html.Partial and Html.RenderPartial in asp.net mvc? also What is difference between Html.Action and Html.RenderAction in asp.net mvc?

Answered By: GvS ( 247)

Html.Partial returns a string, Html.RenderPartial calls Write internally, and returns void.

The usage (using Razor syntax):

@Html.Partial("ViewName")

@{ Html.RenderPartial("ViewName");  }

The usage (using WebForms syntax):

<%: Html.Partial("ViewName") %>

<% Html.RenderPartial("ViewName"); %>

Will do exactly the same.

You can store the output of Html.Partial in a variable, or return it from a function. You cannot do this with Html.RenderPartial. The result will be written to the Response stream during the execution.

The same is true for Html.Action and Html.RenderAction.

I am just getting started on ASP.NET MVC so bear with me. I've searched around this site and various others and have seen a few implementations of this.

EDIT: I forgot to mention I am using RC2

Using URL Routing:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

The above seems to take care of requests like this (assuming default route tables setup by initial MVC project): "/blah/blah/blah/blah"

Overriding HandleUnknownAction() in the controller itself:

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

However the previous strategies do not handle a request to a Bad/Unknown controller. For example, I do not have a "/IDoNotExist", if I request this I get the generic 404 page from the web server and not my 404 if I use routing + override.

So finally, my question is: Is there any way to catch this type of request using a route or something else in the MVC framework itself?

OR should I just default to using Web.Config customErrors as my 404 handler and forget all this? I assume if I go with customErrors I'll have to store the generic 404 page outside of /Views due to the Web.Config restrictions on direct access. Anyway any best practices or guidance is appreciated.

Answered By: Shay Jacoby ( 140)

The code is taken from http://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspx and works in ASP.net MVC 1.0 as well

Here's how I handle http exceptions:

protected void Application_Error(object sender, EventArgs e)
{
   Exception exception = Server.GetLastError();
   // Log the exception.

   ILogger logger = Container.Resolve<ILogger>();
   logger.Error(exception);

   Response.Clear();

   HttpException httpException = exception as HttpException;

   RouteData routeData = new RouteData();
   routeData.Values.Add("controller", "Error");

   if (httpException == null)
   {
       routeData.Values.Add("action", "Index");
   }
   else //It's an Http Exception, Let's handle it.
   {
       switch (httpException.GetHttpCode())
       {
          case 404:
              // Page not found.
              routeData.Values.Add("action", "HttpError404");
              break;
          case 500:
              // Server error.
              routeData.Values.Add("action", "HttpError500");
              break;

           // Here you can handle Views to other error codes.
           // I choose a General error template  
           default:
              routeData.Values.Add("action", "General");
              break;
      }
  }           

  // Pass exception details to the target error View.
  routeData.Values.Add("error", exception);

  // Clear the error on server.
  Server.ClearError();

  // Avoid IIS7 getting in the middle
  Response.TrySkipIisCustomErrors = true; 

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData));
}

I am going to be starting up a new project at work and want to get into unit testing. We will be using VS 2008, C#, and the ASP.NET MVC stuff. I am looking at using either NUnit or the built in test projects that VS2008 has, but I am open to researching other suggestions. Is one system better than the other or perhaps easier to use/understand than the other? I am looking to get this project set up as kind of the "best practice" for our development efforts going forward.

Thanks for any help and suggestions!!

Answered By: Mendelt ( 83)

Daok named all the pro's of VS2008 test projects, here are the pro's of NUnit.

  • NUnit has a mocking framework.
  • NUnit can be run outside of the IDE, this can be useful if you want to run tests on a non MS build server like CC.Net
  • NUnit has more versions coming out than visual studio. You don't have to wait years for a new version And you don't have to install a new version of the IDE to get new features.
  • There are extensions being developed for NUnit like row-tests etc.
  • Visual Studio tests take a long time to start up for some reason. This is better in 2008 but still too slow for my taste. Quickly running a test to see if you didn't break something can take too long. NUnit with something like Testdriven.Net to run tests from the IDE is actually much faster. especially when running single tests.
    Accorting to Kjetil Klaussen this is caused by the Visual Studio testrunner, running MSTest tests in TestDriven.Net makes MSTest performance comparable to NUnit.
193
Spoike

Is there some easy way to handle multiple submit buttons from the same form? Example:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>

Any idea how to do this in ASP.NET Framework Beta? All examples I've googled for have single buttons in them.

Answered By: Trevor de Koekkoek ( 78)

You can check the name in the action as has been mentioned, but you might consider whether or not this is good design. It is a good idea to consider the responsibility of the action and not couple this design too much to UI aspects like button names. So consider using 2 forms and 2 actions:

<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>

<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

Also, in the case of "Cancel", you are usually just not processing the form and are going to a new URL. In this case you do not need to submit the form at all and just need a link:

<%=Html.ActionLink("Cancel", "List", "MyController") %>