Best asp.net questions in January 2011

How are threads tied to requests through Http.sys, IIS and ASP.NET

11 votes

I'm currently reading a lot about node.js. There is a frequent comparison between servers using a traditional thread per request model (Apache), and servers that use an event loop (Nginx, node, Tornado).

I would like to learn in detail about how a request is processed in ASP.NET - from the point it is received in http.sys all the way up to it being processed in ASP.NET itself. I've found the MSDN documentation on http.sys and IIS a little lacking, but perhaps my google-fu is weak today. So far, the best resource I have found is a post on Thomas Marquardt's Blog.

Could anyone shed more light on the topic, or point me to any other resources?

(For the purposes of this question I'm only interested in IIS7 with a typical integrated pipeline)

From my research so far, its my understanding that when a request comes in it gets put into a kernel-mode request queue. According to this, this avoids many of the problems with context switching when there are massive amounts of requests (or processes or threads...), providing similar benefits to evented IO. Quoted from the article:

"Each request queue corresponds to one application pool. An application pool corresponds to one request queue within HTTP.sys and one or more worker processes."

So according to that, every request queue may have more than one "Worker Process." (Google cache) More on worker processes

From my understanding:

  • IIS Opens creates a request queue (see the http.sys api below)
  • A "Web Site" configured in IIS corresponds to one Worker Process
  • A Web Site/Worker Process shares the Thread Pool.
  • A thread is handed a request from the request queue.

Here is a lot of great information about IIS7's architecture

Here is some more information about http.sys.

Open questions i still have:

  • How the heck does IIS change the Server header if it Uses HTTP.SYS? (See this question)

Note: I am not sure if/how a "Kernel-mode request queue" corresponds to an IO completion port, I would assume that each request would have its own but I don't know, so I truly hope someone will answer this more thoroughly. I just stumbled on this question and it seems that http.sys does in fact use IO Completion ports, which should provide nearly all of the same benifits that evented IO (node.js, nginx, lighttpd, C10K, etc...) have.

What's the difference between ViewData and ViewBag?

10 votes

I saw the ViewBag in MVC3? How's that different than Viewdata in MVC2?

It uses the C# 4.0 dynamic feature. It achieves the same goal as viewdata and should be avoided in favor of using strongly typed view models (the same way as viewdata should be avoided).

So basically it replaces magic strings:

ViewData["foo"]

with magic properties:

ViewBag.Foo

for which you have no compile time safety.

I continue to blame Microsoft for ever introducing this concept in MVC.

Why does Razor _layout.cshtml have a leading underscore in file name?

9 votes

In the default ASP.NET MVC 3 project, layout & partial cshtml files start with an underscore

  • _viewstart
  • _Layout
  • _LogOnPartial

What is this convention mean, and what is used for? Do I need to follow this convention?

Does the framework give some special meaning to a .cshtml file that begins with an underscore?

Razor was developed for ASP.NET Web Pages (WebMatrix), which doesn't have the same sort of protection built in regarding Views folders and Routing that you get within MVC. Since layout pages in Web Pages are not intended to be served directly, they are prefixed with the underscore. And Web Pages has been configured not to allow files with leading underscores in their names from being executed. Other .cshtml files within Web Pages generally need to be browsable. They are the equivalent of .asp or .php files.

The ASP.NET team have stated that Web Pages is a starting point within ASP.NET development, which should lead to migration to MVC in time (for those that want to move on). Part of that means that it should be as easy as possible to migrate from Web Pages to MVC. Consequently, it makes sense to carry over naming conventions established within Web Pages to MVC Razor files.

So there is a technical reason for prefixing the file names with an underscore - it just isn't relevant to MVC.

List of what each of <% means (<%#, <%=, etc...)

9 votes

Possible Duplicate:
ASP.NET “special” tags

You know how you can embed property value from code-behind in your page by simply using <%= PropertyFromCodeBehind %> in your .aspx?

Well, I only recently discovered that and I can't seem to find any tutorial that would explain this (and related stuff) in more depth (I only know that <%# is used in conjuction with Eval) - probably because I'm using <% for searches.

So, can anybody provide me with more detail explanation of these tags, or give a link to some tutorial that explains all this? I'm interested in anything that can be learned on this subject; somewhere I saw that you can do fancy stuff like <% for ... %>.

Here is a good place to get started.

There are several different syntaxes:

  • <%$ %> Expression Syntax
  • <%# %> Data-Binding syntax
  • <% %> Evaluated Code Blocks
  • <%= %> Statement and Expression

New to ASP.NET 4 is the HTML encoding syntax (haacked). This is the same as <%= %> except the result is HTML encoded (for non IHtmlString types). The new syntax is intended to replace <%= %>.

  • <%: %> HTML Encoded output

How to remove or compress your asp.net viewstate

9 votes

Just spent a lot of time exorcising asp.net's large (but understandably useful) viewstate from an app, and i think it's worth sharing how it's done.

Basically, i want this question to be open to all solutions for shrinking/compressing/removing viewstate.

Another better option, roll your own PageStatePersister. Here's mine, heavily inspired by http://aspalliance.com/72:

using System.Web.UI;

... in your page class:

PageStatePersister pageStatePersister;
protected override PageStatePersister PageStatePersister
{
  get
  {
    // Unlike as exemplified in the MSDN docs, we cannot simply return a new PageStatePersister
    // every call to this property, as it causes problems
    return pageStatePersister ?? (pageStatePersister = new BetterSessionPageStatePersister(this));
  }
}

... in your BetterSessionPageStatePersister.cs:

/// <summary>
/// This class allows the viewstate to be kept server-side, so that postbacks are as small as possible.
/// It is similar to the built-in 'SessionPageStatePersister', but it yields smaller postbacks,
/// because the SessionPageStatePersister still leaves some viewstate (possibly it leaves the controlstate)
/// in the postback.
/// </summary>
class BetterSessionPageStatePersister : PageStatePersister
{
  public BetterSessionPageStatePersister(Page page)
    : base(page)
  { }

  const string ViewStateFieldName = "__VIEWSTATEKEY";
  const string ViewStateKeyPrefix = "ViewState_";
  const string RecentViewStateQueue = "ViewStateQueue";
  const int RecentViewStateQueueMaxLength = 5;

  public override void Load()
  {
    // The cache key for this viewstate is stored in a hidden field, so grab it
    string viewStateKey = Page.Request.Form[ViewStateFieldName] as string;

    // Grab the viewstate data using the key to look it up
    if (viewStateKey != null)
    {
      Pair p = (Pair)Page.Session[viewStateKey];
      ViewState = p.First;
      ControlState = p.Second;
    }
  }

  public override void Save()
  {
    // Give this viewstate a random key
    string viewStateKey = ViewStateKeyPrefix + Guid.NewGuid().ToString();

    // Store the view and control state
    Page.Session[viewStateKey] = new Pair(ViewState, ControlState);

    // Store the viewstate's key in a hidden field, so on postback we can grab it from the cache
    Page.ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey);

    // Some tidying up: keep track of the X most recent viewstates for this user, and remove old ones
    var recent = Page.Session[RecentViewStateQueue] as Queue<string>;
    if (recent == null) Page.Session[RecentViewStateQueue] = recent = new Queue<string>();
    recent.Enqueue(viewStateKey); // Add this new one so it'll get removed later
    while (recent.Count > RecentViewStateQueueMaxLength) // If we've got lots in the queue, remove the old ones
      Page.Session.Remove(recent.Dequeue());
  }
}

Is Mono's VB.Net support ready for a production site?

9 votes

Previously, I've only used Microsoft-centric solutions, but for an upcoming ASP.Net project I'm considering using Mono and hosting it on a Linux Amazon EC2 instance. Based on the responses to my previous question, this sounds doable. However, I'm most comfortable with VB.Net and I'm wondering how well Mono supports it.

Does anyone have first-hand experience writing ASP.Net applications for Mono using VB.Net? If so, I'd like to know how it went, what kind of compatibility issues you ran into, and if you consider Mono's VB.Net support ready for use on a production site?

I know Mono's C#.Net support is very good, so that's my fall-back plan, but I'd really prefer to use VB.Net.

The VB compiler hasn't been abandoned, it's just a lack of time that is preventing the required work to update to newer VB versions.

Currently vbnc has support for VB 8 (aka Visual Studio 2005), with a few minor features from newer VB versions.

The easiest and safest would be to precompile your site on Windows, in which case you won't have to deal with any potential compiler issues (and you can use the most recent Visual Studio version). If you take this route you shouldn't run into any bugs you wouldn't hit using C# [1]

[1]: You'd be referencing one assembly more: Microsoft.VisualBasic.dll, which could be a source of bugs - but if you adhere to what is considered good programming practice for VB (turn on Option Strict) the chances that you'll hit any significant new bugs is pretty low.

How to keep validation DRY?

8 votes

Using this approach to view models in MVC: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/29/how-we-do-mvc-view-models.aspx

leaves an unanswered question in my mind. So it is about time I had it cleared up.

If I'm using auto mapper to map domain properties to a dto, then I appreciate that my domain layer can return a set of validation rules when the dto is mapped to a domain entity which is saved.

But, I don't see a DRY way of getting client validation to work and adding the errors to model state so they correspond to the correct property on the view model.

Cheers

I found a related question with some interesting responses:

Mapping Validation Attributes From Domain Entity to DTO

I've been thinking about this, and in a way it is analogous to the situation we have with server-side and client-side validation. (e.g. Using both NHibernate Validator and jQuery.validate).

These days it's pretty well accepted that you should have a full set of server-side validation, and adding client-side validation is an option you can choose in order to make your application more user-friendly. It used to be that you had to implement your client-side validation manually, but you accepted the duplication of work because of the benefit in usability.

I'd argue that what we're dealing with here is very similar. You should have validation in your domain layer. You can't rely on the consuming applications to always add the validation themselves.

You then have the option in your application of adding validation on your DTO/view models. You do this because it's more helpful to deal with validation errors in the view rather than letting them get through to the domain which could throw an exception or give a less helpful error message. The point is that from the domain perspective you don't rely on this being done. You're still confident in your system because you know if any bad data does get through, your model will catch it.

The client/server case is a non-issue these days because so much work has been done to automate it, generating the client-side code from the server-side code (e.g. ModelValidatorProvider in ASP.Net MVC). I believe that as more and more people take up the use of view models/DTOs we'll start to see similar solutions for mapping domain validation onto the DTOs automatically (it's already happening with AutoMapper).

So in short, my (pragmatic rather than ideal ;)) answer is:

Accept the violation of DRY for now, do validation in both places, and try to contribute to projects that aim to automate it in future

Recommended approach to port to ASP.NET MVC

7 votes

I think many of us used to face the same question: what's the best practice to port existing web forms App to MVC. The situation for me is that we'll support both web forms and MVC at the same time. It means, we create new features in MVC, while maintaining legacy pages in web forms, and they're all in a same project.

The point is: we want to keep the DRY (do not repeat yourself) principle and reduce duplicate code as much as possible. The ASPX page is not a problem as we only create new features in MVC, but there're still some shared components we want to re-use the both new / legacy pages:

  • Master page
  • UserControl

The question here is: Is that possible to create a common master page / usercontrol that could be used for both web forms and MVC? I know that ViewMasterPage inherits from MasterPage and ViewUserControl inherits from UserControl, so it's maybe OK to let both web forms and MVC ASPX page refer to the MVC version. I did some testing and found sometimes it generates errors during the rendering of usercontrols.

Any idea / experience you can share with me? Very appreciate to it.


Background:

This UI project has been created for years and there're 20+ people working on that. Before I start the common master page trial, there're about 50+ web forms pages and only one MVC page. We create new features on MVC, but the old pages keep remaining in web forms.

This situation will keep for a long time, probably because this's a business-driven company so new features are always in a higher priority. This means we need to support both at the same time.

Sharing MasterPages: see this thread.

User Controls:

This is one of the banes of my existence with MVC; in MVC2 and previous revs, there's no direct equivalent to webforms user controls. A sort-of workaround is creating HtmlHelpers - (effectively extension methods to the Html object available in views that return HTML), but that means you'll have to render your HTML in code. Teh suck.

With MVC3 and the Razor view engine, a new class of Html Helpers is available that provides most of the benefits of user controls, including the ability to place them in separate assemblies (and therefore can be used in multiple projects). I'll see if I can dig up an example link, but Scott Guthrie's blog had an example in one of his recent MVC3/Razor posts.

How do you actually perform relationships in Entity Framework 4 Code-First CTP 5 ?

7 votes

Hello,

I would like to have a short example on how do you actually perform relationships in Entity Framework 4 Code-First CTP 5 ?

Would love an example for these kind of relations :

* one-to-many
* many-to-many

Thanks a lots!

One to One

public class One
{
  public int Id {get;set;}
  public virtual Two RelationTwo {get;set;}
}

public class Two
{
 public int Id {get;set;}
 public virtual One RelationOne {get;set;}
}

Things to note, it has to be virtual

One to Many

public class One
{
  public int Id {get;set;}
  public virtual ICollection<Two> RelationTwo {get;set;}
}

public class Two
{
 public int Id {get;set;}
 public virtual One RelationOne {get;set;}
}

Many to Many

public class One
{
  public int Id {get;set;}
  public virtual ICollection<Two> RelationTwo {get;set;}
}

public class Two
{
 public int Id {get;set;}
 public virtual ICollection<One> RelationOne {get;set;}
}

note that it needs to be ICollection

Following links maybe helpful, click and click

Hope this helps.

EDIT

Updated to include one to many.

EDIT #2

Updated to include a potential for doing the Invoice <-> Product scenario which was requested by comment.

note: this is untested, but should put you in the right direction

public class Invoice
{
    public int Id {get;set;}
    //.. etc. other details on invoice, linking to shipping address etc.

    public virtual ICollection<InvoiceProduct> Items {get;set;}
}

public class InvoiceProduct
{
    public int Id {get;set;}
    public int Quantity {get;set;}
    public decimal Price {get;set;} // possibly calculated
    //.. other details such as discounts maybe

    public virtual Product Product {get;set;}
    public virtual Invoice Order {get;set;} // maybe but not required
}

public class Product
{
    public int Id {get;set;}
    //.. other details about product
}

Using this you could then iterate through all the items on the invoice and then foreach be able to show the invoice details about each item as well as a description from the product itself.

ASP.NET/SQL 2008 Performance Problem

7 votes

We've developed a system with a search screen that looks a little something like this:

As you can see, there is some fairly serious search functionality. You can use any combination of statuses, channels, languages, campaign types, and then narrow it down by name and so on as well.

Then, once you've searched and the leads pop up at the bottom, you can sort the headers.

The query uses ROWNUM to do a paging scheme, so we only return something like 70 rows at a time.

The Problem

Even though we're only returning 70 rows, an awful lot of IO and sorting is going on. This makes sense of course.

This has always caused some minor spikes to the Disk Queue. It started slowing down more when we hit 3 million leads, and now that we're getting closer to 5, the Disk Queue pegs for up to a second or two straight sometimes.

That would actually still be workable, but this system has another area with a time-sensitive process, lets say for simplicity that it's a web service, that needs to serve up responses very quickly or it will cause a timeout on the other end. The Disk Queue spikes are causing that part to bog down, which is causing timeouts downstream. The end result is actually dropped phone calls in our automated VoiceXML-based IVR, and that's very bad for us.

What We've Tried

We've tried:

  • Maintenance tasks that reduce the number of leads in the system to the bare minimum.
  • Added the obvious indexes to help.
  • Ran the index tuning wizard in profiler and applied most of its suggestions. One of them was going to more or less reproduce the entire table inside an index so I tweaked it by hand to do a bit less than that.
  • Added more RAM to the server. It was a little low but now it always has something like 8 gigs idle, and the SQL server is configured to use no more than 8 gigs, however it never uses more than 2 or 3. I found that odd. Why isn't it just putting the whole table in RAM? It's only 5 million leads and there's plenty of room.
  • Poured over query execution plans. I can see that at this point the indexes seem to be mostly doing their job -- about 90% of the work is happening during the sorting stage.
  • Considered partitioning the Leads table out to a different physical drive, but we don't have the resources for that, and it seems like it shouldn't be necessary.

In Closing...

Part of me feels like the server should be able to handle this. Five million records is not so many given the power of that server, which is a decent quad core with 16 gigs of ram. However, I can see how the sorting part is causing millions of rows to be touched just to return a handful.

So what have you done in situations like this? My instinct is that we should maybe slash some functionality, but if there's a way to keep this intact that will save me a war with the business unit.

Thanks in advance!

Database bottlenecks can frequently be improved by improving your SQL queries. Without knowing what those look like, consider creating an operational data store or a data warehouse that you populate on a scheduled basis.

Sometimes flattening out your complex relational databases is the way to go. It can make queries run significantly faster, and make it a lot easier to optimize your queries, since the model is very flat. That may also make it easier to determine if you need to scale your database server up or out. A capacity and growth analysis may help to make that call.

Transactional/highly normalized databases are not usually as scalable as an ODS or data warehouse.

Edit: Your ORM may have optimizations as well that it may support, that may be worth looking into, rather than just looking into how to optimize the queries that it's sending to your database. Perhaps bypassing your ORM altogether for the reports could be one way to have full control over your queries in order to gain better performance.

ASP.NET MVC - Alternative to Role Provider?

7 votes

Hey there,

I'm trying to avoid the use of the Role Provider and Membership Provider since its way too clumsy in my opinion, and therefore I'm trying to making my own "version" which is less clumsy and more manageable/flexible. Now is my question.. is there an alternative to the Role Provider which is decent? (I know that I can do custom Role provier, membership provider etc.)

By more manageable/flexible I mean that I'm limited to use the Roles static class and not implement directly into my service layer which interact with the database context, instead I'm bound to use the Roles static class which has its own database context etc, also the table names is awful..

Thanks in advance.

I'm in the same boat as you - I've always hated the RoleProviders. Yeah, they're great if you want to get things up and running for a small website, but they're not very realistic. The major downside I've always found is that they tie you directly to ASP.NET.

The way I went for a recent project was defining a couple of interfaces that are part of the service layer (NOTE: I simplified these quite a bit - but you could easily add to them):

public interface IAuthenticationService
{
    bool Login(string username, string password);
    void Logout(User user);
}

public interface IAuthorizationService
{
    bool Authorize(User user, Roles requiredRoles);
}

Then your users could have a Roles enum:

public enum Roles
{
    Accounting = 1,
    Scheduling = 2,
    Prescriptions = 4
    // What ever else you need to define here.
    // Notice all powers of 2 so we can OR them to combine role permissions.
}

public class User
{
    bool IsAdministrator { get; set; }
    Roles Permissions { get; set; }
}

For your IAuthenticationService, you could have a base implementation that does standard password checking and then you could have a FormsAuthenticationService that does a little bit more such as setting the cookie etc. For your AuthorizationService, you'd need something like this:

public class AuthorizationServiceService : IAuthorizationService
{
    public bool Authorize(User userSession, Roles requiredRoles)
    {
        if (userSession.IsAdministrator)
        {
            return true;
        }
        else
        {
            // Check if the roles enum has the specific role bit set.
            return (requiredRoles & user.Roles) == requiredRoles;
        }
    }
}

On top of these base services, you could easily add services to reset passwords etc.

Since you're using MVC, you could do authorization at the action level using an ActionFilter:

public class RequirePermissionFilter : IAuthorizationFilter
{
    #region Fields

    private readonly IAuthorizationService authorizationService;
    private readonly Roles permissions;

    #endregion

    #region Constructors

    public RequirePermissionFilter(IAuthorizationService authorizationService, Roles requiredRoles)
    {
        this.authorizationService = authorizationService;
        this.permissions = requiredRoles;
        this.isAdministrator = isAdministrator;
    }

    #endregion

    #region Methods

    private IAuthorizationService CreateAuthorizationService(HttpContextBase httpContext)
    {
        return this.authorizationService ?? new FormsAuthorizationService(httpContext);
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var authSvc = this.CreateAuthorizationService(filterContext.HttpContext);
        // Get the current user... you could store in session or the HttpContext if you want too. It would be set inside the FormsAuthenticationService.
        var userSession = (User)filterContext.HttpContext.Session["CurrentUser"];

        var success = authSvc.Authorize(userSession, this.permissions);

        if (success)
        {
            // Since authorization is performed at the action level, the authorization code runs
            // after the output caching module. In the worst case this could allow an authorized user
            // to cause the page to be cached, then an unauthorized user would later be served the
            // cached page. We work around this by telling proxies not to cache the sensitive page,
            // then we hook our custom authorization code into the caching mechanism so that we have
            // the final say on whether or not a page should be served from the cache.
            var cache = filterContext.HttpContext.Response.Cache;
            cache.SetProxyMaxAge(new TimeSpan(0));
            cache.AddValidationCallback((HttpContext context, object data, ref HttpValidationStatus validationStatus) =>
            {
                validationStatus = this.OnCacheAuthorization(new HttpContextWrapper(context));
            }, null);
        }
        else
        {
            this.HandleUnauthorizedRequest(filterContext);
        }
    }

    private void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // Ajax requests will return status code 500 because we don't want to return the result of the
        // redirect to the login page.
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new HttpStatusCodeResult(500);
        }
        else
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

    public HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
    {
        var authSvc = this.CreateAuthorizationService(httpContext);
        var userSession = (User)httpContext.Session["CurrentUser"];

        var success = authSvc.Authorize(userSession, this.permissions);

        if (success)
        {
            return HttpValidationStatus.Valid;
        }
        else
        {
            return HttpValidationStatus.IgnoreThisRequest;
        }
    }

    #endregion
}

Which you can then decorate on your controller actions:

[RequirePermission(Roles.Accounting)]
public ViewResult Index()
{
   // ...
}

The advantage of this approach is you can also use dependency injection and an IoC container to wire things up. Also, you can use it across multiple applications (not just your ASP.NET one). You would use your ORM to define the appropriate schema.

If you need more details around the FormsAuthorization/Authentication services or where to go from here, let me know.

EDIT: To add "security trimming", you could do it with an HtmlHelper. This probably needs a little more... but you get the idea.

public static bool SecurityTrim<TModel>(this HtmlHelper<TModel> source, Roles requiredRoles)
{
    var authorizationService = new FormsAuthorizationService();
    var user = (User)HttpContext.Current.Session["CurrentUser"];
    return authorizationService.Authorize(user, requiredRoles);
}

And then inside your view (using Razor syntax here):

@if(Html.SecurityTrim(Roles.Accounting))
{
    <span>Only for accounting</span>
}

EDIT: The UserSession would look something like this:

public class UserSession
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public bool IsAdministrator { get; set; }
    public Roles GetRoles()
    {
         // make the call to the database or whatever here.
         // or just turn this into a property.
    }
}

This way, we don't expose the password hash and all other details inside the session of the current user since they're really not needed for the user's session lifetime.

How to unit test ValueProviderFactories in ASP.NET MVC3?

6 votes

We wanted to upgrade our projects from ASP.NET MVC 2 to 3. Most of our tests succeeded, but there are some that fail on ValueProviderFactories.Factories.GetValueProvider(context).

Here is a simple test class that ilustrates the problem.

[TestFixture]
public class FailingTest
{
  [Test]
  public void Test()
  {
    var type = typeof(string);
    // any controller
    AuthenticationController c = new AuthenticationController();
    var httpContext = new Mock<HttpContextBase>();
    var context = c.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), c);

    IModelBinder converter = ModelBinders.Binders.GetBinder(type);
    var bc = new ModelBindingContext
    {
      ModelName = "testparam",
      ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, type),
      ValueProvider = ValueProviderFactories.Factories.GetValueProvider(context)
    };
    Console.WriteLine(converter.BindModel(context, bc));
  }
}

Exception "Object reference not set to an instance of an object." is thrown when ValueProviderFactories.Factories.GetValueProvider(context) is called. The stacktrace looks like this:

Microsoft.Web.Infrastructure.dll!Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(System.Web.HttpContext context) + 0x23 bytes   
Microsoft.Web.Infrastructure.dll!Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(System.Web.HttpContext context, out System.Collections.Specialized.NameValueCollection form, out System.Collections.Specialized.NameValueCollection queryString, out System.Collections.Specialized.NameValueCollection headers, out System.Web.HttpCookieCollection cookies) + 0xbe bytes    
System.Web.WebPages.dll!System.Web.Helpers.Validation.Unvalidated(System.Web.HttpRequest request) + 0x73 bytes  
System.Web.WebPages.dll!System.Web.Helpers.Validation.Unvalidated(System.Web.HttpRequestBase request) + 0x25 bytes  
System.Web.Mvc.DLL!System.Web.Mvc.FormValueProviderFactory..ctor.AnonymousMethod__0(System.Web.Mvc.ControllerContext cc) + 0x5a bytes   
System.Web.Mvc.DLL!System.Web.Mvc.FormValueProviderFactory.GetValueProvider(System.Web.Mvc.ControllerContext controllerContext) + 0xa0 bytes    
System.Web.Mvc.DLL!System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider.AnonymousMethod__7(System.Web.Mvc.ValueProviderFactory factory) + 0x4a bytes  
System.Core.dll!System.Linq.Enumerable.WhereSelectEnumerableIterator<System.Web.Mvc.ValueProviderFactory,<>f__AnonymousType2<System.Web.Mvc.ValueProviderFactory,System.Web.Mvc.IValueProvider>>.MoveNext() + 0x24d bytes   
System.Core.dll!System.Linq.Enumerable.WhereSelectEnumerableIterator<<>f__AnonymousType2<System.Web.Mvc.ValueProviderFactory,System.Web.Mvc.IValueProvider>,System.Web.Mvc.IValueProvider>.MoveNext() + 0x2ba bytes 
mscorlib.dll!System.Collections.Generic.List<System.Web.Mvc.IValueProvider>.List(System.Collections.Generic.IEnumerable<System.Web.Mvc.IValueProvider> collection) + 0x1d8 bytes    
System.Core.dll!System.Linq.Enumerable.ToList<System.Web.Mvc.IValueProvider>(System.Collections.Generic.IEnumerable<System.Web.Mvc.IValueProvider> source) + 0xb5 bytes 
System.Web.Mvc.DLL!System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(System.Web.Mvc.ControllerContext controllerContext) + 0x24d bytes 
test.DLL!FailingTest.Test() Line 31 + 0xf9 bytes    C#

I wanted to know the reason why it throws the exception and saw:

public static ValidationUtility.UnvalidatedCollections GetUnvalidatedCollections(HttpContext context)
{
    return (ValidationUtility.UnvalidatedCollections) context.Items[_unvalidatedCollectionsKey];
}

So, are we back in past when we were dependent on HttpContext.Current? How to workaround it?

This can easily be solved by prox-ing ValueProviders that access HttpContext to a the one ignoring it.

I have explained everything in my blog post: Unit test actions with ValueProviderFactories in ASP.NET MVC3.

The key is this code:

public static class ValueProviderFactoresExtensions {
    public static ValueProviderFactoryCollection ReplaceWith<TOriginal>(this ValueProviderFactoryCollection factories, Func<ControllerContext, NameValueCollection> sourceAccessor) {
        var original = factories.FirstOrDefault(x => typeof(TOriginal) == x.GetType());
        if (original != null) {
            var index = factories.IndexOf(original);
            factories[index] = new TestValueProviderFactory(sourceAccessor);
        }
        return factories;
    }

    class TestValueProviderFactory : ValueProviderFactory {
        private readonly Func<ControllerContext, NameValueCollection> sourceAccessor;


        public TestValueProviderFactory(Func<ControllerContext, NameValueCollection> sourceAccessor) {
            this.sourceAccessor = sourceAccessor;
        }


        public override IValueProvider GetValueProvider(ControllerContext controllerContext) {
            return new NameValueCollectionValueProvider(sourceAccessor(controllerContext), CultureInfo.CurrentCulture);
        }
    }        
}

So it can be used as:

ValueProviderFactories.Factories
    .ReplaceWith<FormValueProviderFactory>(ctx => ctx.HttpContext.Request.Form)
    .ReplaceWith<QueryStringValueProviderFactory>(ctx => ctx.HttpContext.Request.QueryString);

It was actually very easy :)

Avoid reloading all XML data for each repeater - vb.net

6 votes

I am trying to place a repeater within a repeater using xml data. I have it working exactly as I want, but the method I have used reloads the data for each repeater. I think I need to cast as an XmlNode but I'll be honest - I have no idea where to start.

Here is my code - I'd like to keep everything in the code behind if possible.

<script runat="server">

Public doc As New XmlDocument()

Public Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs)

    If Not Page.IsPostBack then

        doc.Load(Server.MapPath("~/myxml/bookstore.xml"))

        Dim nodes As XmlNodeList = doc.SelectNodes("Bookings/Booking[@CLIENT_NO='SA33762']")
        rpMyRepeater.DataSource = nodes
        rpMyRepeater.DataBind()

    End If

End Sub

   Protected Sub itemDB(ByVal s As Object, ByVal e As RepeaterItemEventArgs)
      If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then

         Dim rpt As Repeater = CType(e.Item.FindControl("books"), Repeater)

         If Not (rpt Is Nothing) Then

            doc.Load(Server.MapPath("~/myxml/bookstore.xml"))

            Dim nodes2 As XmlNodeList = doc.SelectNodes("Bookings/Booking[@CLIENT_NO='SA33762']/Products/Book")

            rpt.DataSource = nodes2
            rpt.DataBind()

         End If

      End If
   End Sub

</script>

Any ideas?

Am I missing something here?

Can't you simply comment/remove your doc.Load(Server.MapPath("~/myxml/bookstore.xml")) out within your itemDB Sub? Since you defined doc "globally" and already loaded it on page load? (by doing that you will already avoid reloading the xml)

That said, I do agree with Caspar that you should rather use the XmlDatasource (especially for its caching abilities), you don't have to use the XmlDatasource within your markup - you can always define it within your code-behind as well - Since you're concerned about people seeing your (asp.net server-side based) markup for some reason...

e.g.

Public Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs) Handles Me.Load

    If Not Page.IsPostBack Then
        Dim source As New XmlDataSource()
        source.DataFile = "~/myxml/bookstore.xml"
        source.XPath = "Bookings/Booking[@CLIENT_NO='SA33762']"
        rpMyRepeater.DataSource = source
        rpMyRepeater.DataBind()
    End If

End Sub

Markup: (Nice thing you'll notice here, is that we bind the second repeater using the source from the first repeater)

<asp:Repeater ID="rpMyRepeater" runat="server">
    <ItemTemplate>
        <%#XPath("//Booking/NAME/text()")%>
        <asp:Repeater runat="server" ID='books' DataSource='<%#XPathSelect("//Booking/Products/Book") %>'>
            <HeaderTemplate>
                <h2>
                    Books</h2>
            </HeaderTemplate>
            <ItemTemplate>
                <p>
                    Title:
                    <%#XPath("TITLE/text()")%></p>
                <p>
                    <%#XPath("BOOKCODE/text()")%></p>
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>

XML

<?xml version="1.0" encoding="utf-8" ?>
<Bookings>
  <Booking CLIENT_NO="SA33762">
    <NAME>Mr Pf_Test_15033</NAME>
    <Products>
      <Book>
        <TITLE>My Book</TITLE>
        <BOOKCODE>12345</BOOKCODE>
      </Book>
      <Book>
        <TITLE>My Book2</TITLE>
        <BOOKCODE>123456</BOOKCODE>
      </Book>
    </Products>
  </Booking>
</Bookings>

The implementation using the ListView control (one of my favorite asp.net control) will look something like this: (If there's no books available, it will display the markup within the EmptyDataTemplate)

<asp:Repeater ID="rpMyRepeater" runat="server">
    <ItemTemplate>
        <%#XPath("//Booking/NAME/text()")%>
        <asp:ListView runat="server" ID="books" ItemPlaceholderID="phItems" DataSource='<%#XPathSelect("//Booking/Products/Book") %>'>
            <LayoutTemplate>
                <h2>
                    Books</h2>
                <asp:PlaceHolder runat="server" ID="phItems"></asp:PlaceHolder>
            </LayoutTemplate>
            <ItemTemplate>
                <p>
                    Title:
                    <%#XPath("TITLE/text()")%></p>
                <p>
                    <%#XPath("BOOKCODE/text()")%></p>
            </ItemTemplate>
            <EmptyDataTemplate>
                <p>
                    Sorry no books available</p>
            </EmptyDataTemplate>
        </asp:ListView>
    </ItemTemplate>
</asp:Repeater>

Should I learn asp.NET MVC 3 without knowledge of MVC 1 or 2?

6 votes

Hi guys,

FYI, I know asp.NET and planning to learn asp.NET MVC. I heard that asp.NET MVC 3 has been released . Should I learn MVC 3 right now? or should I start with MVC 1 or 2?

Thanks

The core principles are all the same so learning MVC 3 would be the way to go. "Learning" 1 or 2 first would just mean you'd initial knowledge of the framework is already out of date. I always advice against learning older versions of frameworks because you often have to unlearn things when you get to the newest version of the framework

jQuery with Microsoft - Tutorials/Resources?

4 votes

Can anyone suggest some resources (books/videos/tutorials) that focus on using jQuery with classic ASP and ASP.NET? Having used ASP.NET AJAX a while back I find things are quite a bit different now with Microsoft embracing jQuery and deprecating ASP.NET AJAX. Thank you.

Update

I have never been a fan of the AJAX implementation supported by Microsoft (ScriptManager, UpdatePanel, etc ..). Now with Microsoft seemingly abandoning these controls (i.e. ASP.NET AJAX Control Toolkit) and embracing jQuery I am looking for tutorials and/or articles that cover to implement AJAX within ASP.NET application using jQuery.

try the following:

Using jQuery with ASP .NET
Using jQuery with ASP.NET Part 2: Making Ajax Callbacks to the Server
(first part makes introduction to jQuery)

about books, I don't know any dedicated to using jQuery with ASP.NET, there is one eBook jQuery for ASP.NET Developers, but looking at Table of Contents, it is mostly about jQuery, only few pages described its using with ASP.NET, and I'm not sure it is worth to buy