Best asp.net questions in February 2011

Best way to get a date with .NET?

11 votes

I'm getting a string back from my page and I want to make sure it's a date. This is what I have so far (it works) and I just want to know if this is the "best" way to do it. I'm using .NET 4.

int TheMonth =0;
int TheDay = 0;
int TheYear = 0;
DateTime NewDate;

var TheIncomingParam = Request.Params.Get("__EVENTARGUMENT").ToString();

char[] TheBreak = { '/' };
string[] TheOutput = TheIncomingParam.Split(TheBreak);

try { TheMonth = Convert.ToInt32(TheOutput[0]); }
catch { }

try { TheDay = Convert.ToInt32(TheOutput[1]); }
catch { }

try { TheYear = Convert.ToInt32(TheOutput[2]); }
catch { }

if (TheMonth!=0 && TheDay!=0 && TheYear!=0)
{
        try { NewDate = new DateTime(TheYear, TheMonth, TheDay); }
        catch { var NoDate = true; }
}

Use one of the Parse methods defined on the DateTime structure.

These will throw an exception if the string is not parseable, so you may want to use one of the TryParse methods instead (not as pretty - they require an out parameter, but are safer):

DateTime myDate;
if(DateTime.TryParse(dateString, 
                  CultureInfo.InvariantCulture, 
                  DateTimeStyles.None, 
                  out myDate))
{
   // Use myDate here, since it parsed successfully
}

If you know the exact format of the passed in date, you can try using the ParseExact or TryParseExact that take date and time format strings (standard or custom) when trying to parse the date string.

Thread Safety and Scope Management for .NET 4.0 ObjectCache

9 votes

Hi Guys,

I'm using the new .NET 4.0 Caching API, ObjectCache. I've asked a few questions on this area the last few days, and i've hinted to this issue - but thought it's worthwhile to break it out into it's own question.

Because the class is abstract and all the methods are virtual, this means we can create our own custom cache providers.

According to MSDN, ObjectCache does not have to be a singleton, and you can create multiple instances of it in your application.

But to me, this sounds like we need to manage the instantiation and lifetime of this object as well?

I have an ASP.NET MVC 3 Web Application, with StructureMap as my dependency injection container.

I want to have a single, shared cache for my entire web application.

So, i create a very simple class which wraps the ObjectCache class, and provides the unboxing in the methods implementation.

The class takes an instance of ObjectCache in the ctor, and sets this to a private static instance of the cache, which the methods (Add, Get, etc) work off.

E.g

public class CacheManager
{
   private static ObjectCache _cache;

   public CacheManager(ObjectCache cache)
   {
      _cache = cache;
   }

   // Add, Get, Remove methods work off _cache instance.
}

Now, here's my DI registry:

For<CacheManager>().Singleton().Use<CacheManager>().Ctor<ObjectCache>("cache").Is(MemoryCache.Default);

In english: When something requests a CacheManager instance, use a singleton instance, and set the ObjectCache parameter to be a MemoryCache instance.

So there's what i have, now the questions:

  1. If i have a class to wrap the ObjectCache, does this class need to be a singleton?
  2. MSDN says ObjectCache is thread-safe, but now that i'm using a singleton, do i need any type of locking to keep the thread safety?
  3. Does the private instance of ObjectCache in my wrapper class need to be static? Does the class itself need to be static?
  4. General thoughts on my overall implementation?

I have not been able to find a decent blog/article on .NET ObjectCache in ASP.NET Web Applications, hence my confusion.

I'm use to using HttpContext.Current.Cache (which is static) and not care about lifetime management for the cache.

  1. Since MemoryCache.Default is a singleton, your stateless class doesn't really need to be one. However, that's completely up to you.
  2. You should not need locking around the ObjectCache instance.
  3. No, and No. Making it static doesn't provide any value. Indicating it's a singleton in StructureMap makes GetInstance<>() always return the same object anyways.
  4. The real value of wrapping ObjectCache would to be abstract the cache implementation so you can change it or mock it. Without an interface this becomes less useful.

An example implementation below...

public interface ICacheManager
{
   // add, get, remove, etc
}

public class CacheManager : ICacheManager
{
   private static ObjectCache _cache;

   public CacheManager(ObjectCache cache)
   {
      _cache = cache;
   }

   // Add, Get, Remove methods work off _cache instance.
}

Then...

For<ICacheManager>()
    .Singleton()
    .Use<CacheManager>();

For<ObjectCache>()
    .Use(MemoryCache.Default);

If you want to change you cache provider that is still an ObjectCache in the future, then it's easy to adjust.

I hope this helps!

Inheritence : is it possible to have over inheritence to be lost in code?

9 votes

Hi all,

I'm currently working on an asp.net site, done by someone else, and it's rediculously over complicated for what it does......Well I think so! Pretty much every class inherits from another class then another and another and so on and on....... You have to go about 8/10 levels on average to get the the base class, sometimes more! And these classes have other classes inside which follow the same pattern of Uber Inheritence. This leaves me lost in code many many times resulting in God knows how many tabs open on visual studio.

Is this good/normal practice or is it bad practice? I feel it's bad practice as something so simple is made over complicated with an over usage of inheritance resulting in un-extensible code...............but I could be wrong :)

Thanks!

Yes, over-using inheritance can lead to a spaghetti warehouse. Inheritance is a tool to allow for encapsulation and abstraction. Abusing it causes too much abstraction and then the purpose of the code becomes unusable. I've seen this pattern abused in imperative constructs as well where a method is passed from method to method to method before an action is actually applied.

private bool getData()
{
    return getOtherData();
}

private bool getOtherData()
{
    return getSomeExtraData();
} 

private bool getSomeExtraData()
{
    return SeeHowTediousThisIs();
}

It all works, but it's just an exceptionally bad architecture for maintenance. I find this often occurs with consultants/contractors attempting to introduce complexity (re: job security).

Enterprise Library validation blocks

8 votes

I've just started using the ms validation blocks which i think are awesome. but have a couple of questions regarding data validation between layers.

Currently I'm using the repository pattern as a bridge to my data access layer. In my logic layer I'm populating my business object and then validating using the validation block before passing it on to my repository layer which in turn passes it on to the data access layer for insertion. Should i validate it again in the repository? If so do i validate using the block again or is there a better way to do it at this level?

As long as you are using a layered architecture where all calls to the repository go through the business layer you do not have to validate it again in the repository.

However, if the repository is being used by other systems that do not go via your business layer, you would need to validate it in the repository layer.

But, that would actually break the DRY Do Not Repeat Yourself principle.

Therefore, if you need to validate in the repository, you should not also do it in the business layer.

None of my "code behind" code is being called.

8 votes

I have just created an ASP.NET C# project and a virtual directory for it in IIS in (as far as I know) the normal way, but I am seeing very strange behavior that I have never seen before.

It seems that none of my C# methods are ever being called. I know this because I have overridden a bunch of methods to do nothing but throw an exception. At least Default.aspx is viewable in the browser (see below)

Here is the exact content of my Default.aspx.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Drawings2
{
    public partial class _Default : System.Web.UI.Page
    {
        static _Default()
        {
            throw new Exception("XXX");
        }
        public _Default()
        {
            throw new Exception("XXX");
        }
        override protected void OnInit(EventArgs e)
        {
            /*
             * base.OnInit(e);
             * InitializeComponent();
             */
            throw new Exception("XXX");
        }
        private void InitializeComponent()
        {
            /*
             * Load += new EventHandler(this.Page_Load);
             */
            throw new Exception("XXX");
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            throw new Exception("XXX");
        }
    }

}

I assume this code is not being loaded at all, because if it was then I would see an exception whenever I tried to view the page in the browser. Instead the content from the .aspx file appears normally (except that my event handlers are not called.)

It gets worse when I try to add new .aspx pages. I get this error when I try to view a new page in the browser (this is with the unmodified .cs file from the VS2008 template): Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately. 

Parser Error Message: Could not load type 'Drawings2.WebForm1'.

What can cause an ASP.NET site to get into this strange state?

Note: <%...%> escapes in the .aspx file still work fine. Also when I add form fields in the .aspx file, I can auto-complete their names in the .cs file. I have tried both true and false for AutoEventWireup on both pages. I have also tried adding and removing "partial" from all class declarations.


Update - here are my @Page tags. As I said, I have tried toggling AutoEventWireup. The referenced .cs files exist and compile with no errors.

<%@ Page Language="C#" AutoEventWireup="false" CodeBehind="Default.aspx.cs" Inherits="Drawings2._Default" %>

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="Drawings2.WebForm1" %>

Update #2 - for the bounty

I have tried used2could's suggestion (replacing CodeBehind with CodeFile) and it does fix this issue (events not firing) however it breaks when I try to use a Master Page.

Whenever I try to view a page whose master page has a CodeFile (as opposed to CodeBehind) I get the following error:

CS0433: The type 'Drawings.Default' exists in both 'c:\Documents and Settings\finnw\Local Settings\Temp\Temporary ASP.NET Files\root\52ab04c4\7135d000\App_Web_default.master.cdcab7d2.6jjbs3wf.dll' and 'c:\Documents and Settings\finnw\Local Settings\Temp\Temporary ASP.NET Files\root\52ab04c4\7135d000\assembly\dl3\6e973316\aa3e8b2f_84e2cb01\Drawings3.DLL'

I have searched various forums for information about this error and none of the suggestions worked (e.g. I tried clearing out the .NET temp directory, restarting IIS and setting Compilation Batch="false".) I am sure it is not because of stale versions of the same class as when I create or rename another master page class the error appears again immediately.

So I need a solution that will:

  • Fire events properly
  • Allow the use of master pages
  • Work with the "ASP.NET Web Application" template (vs. ASP.NET Site)

all simultaneously.

Sounds easy? Please prove it and earn some extra rep (and possibly save my career.)


Related:

There's a lot of conflicting information here. For example, if you are truly creating an ASP.NET Web Application (as opposed to a web site), then you should not be using CodeFile, as used2could suggests.

Have you tried checking the Build Action of your code-behind files? Make sure it is set to Compile.

I think we need to start you from scratch, to identify if the problem is coming from your web project, your IIS configuration, or both.

I'm going to make the following assumptions about your set up, because this is my current set up. Let me know if any of these are wrong, but it shouldn't make a huge difference:

  • You're using Visual Studio 2010 with .NET 3.5
  • Your web server is Windows 2003
  • Your web server is running IIS 6.0

Creating a new web app project:

Let's try to keep this as simple as possible, to minimize any chance of weirdness:

  • Solution 'TestWebApp1'
    • Project 'TestWebApp1' (ASP.NET Web Application)
      • Properties
      • References
      • App_Data
      • Scripts
      • Default.aspx (Build Action: Content)
        • Default.aspx.cs (Build Action: Compile)
      • SiteLayout.Master (Build Action: Content)
        • SiteLayout.Master.cs (Build Action: Compile)
      • Web.config

Contents of Default.aspx:

<%@ Page Title="" Language="C#" MasterPageFile="~/SiteLayout.Master"
    AutoEventWireup="true" CodeBehind="Default.aspx.cs"
    Inherits="TestWebApp1.Default" %>
<asp:Content ID="Content2" ContentPlaceHolderID="mainCPH" runat="server">
    <p><asp:Label ID="lblTest" runat="server">This is a test</asp:Label></p>
</asp:Content>

Contents of Default.aspx.cs:

using System;
namespace TestWebApp1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            lblTest.Text = "Modified from Default.aspx's Page_Load method.";
        }
    }
}

Contents of SiteLayout.Master:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="SiteLayout.master.cs"
    Inherits="TestWebApp1.SiteLayout" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <body>
        <form id="form1" runat="server">
            <div>
                <p><asp:Label ID="lblTest" runat="server">This is a test</asp:Label></p>
                <asp:ContentPlaceHolder ID="mainCPH" runat="server">
                </asp:ContentPlaceHolder>
            </div>
        </form>
    </body>
</html>

Contents of SiteLayout.Master.cs:

using System;
namespace TestWebApp1
{
    public partial class SiteLayout : System.Web.UI.MasterPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            lblTest.Text = "Modified from master page's Page_Load method.";
        }
    }
}

Now, this site should work without fail when debugging in your local computer:

site working locally

Deploying to IIS

  1. Right click on TestWebApp1 project and click Publish.
  2. Choose File System as the 'Publish method' for simplicity.
  3. Enter a path where the files will be deployed.
  4. On your web server, open up IIS (I'm going to assume you're running IIS 6.0)
  5. Under Default Web Site (or whatever site you use), create a new Virtual Directory. Make sure it has permissions to run Scripts.
  6. Copy the files that were published from your dev machine to the IIS virtual directory.
  7. That's it -- your site should be working fine.

Basic VS 2010 Publish Dialog Virtual directory Access Permissions

After following the above steps, are you still getting problems?

How does ASP.NET MVC know how to fill your model to feed your Controller's Action? Does it involve reflection?

8 votes

Having defined a Model

public class HomeModel {
    [Required]
    [Display(Name = "First Name")]
    public string FirstName { get; set; }

    [Required]
    [Display(Name = "Surname")]
    public string Surname { get; set; }
}

and having the following Controller

public class HomeController : Controller {
    [HttpPost]
    public ActionResult Index(HomeModel model) {
        return View(model);
    }

    public ActionResult Index() {

        return View();
    }
}

by some "magic" mechanism HomeModel model gets filled up with values by ASP.NET MVC. Does anyone know how?

From some rudimentary tests, it seems it will look at the POST response and try to match the response objects name with your Model's properties. But to do that I guess it must use reflection? Isn't that inheritably slow?

Thanks

Yes, you are talking about the magic ModelBinder.

ModelBinder is responsible for creating a Model and hydrating it with values from the form post-back and performing validation which its result will appear in ModelState.

Default implementation is DefaultModelBinder but you can plug-in your own.

When will T4MVC support Razor with explicit HtmlHelpers for rendering partials?

7 votes

I've been using T4MVC for some time now and love the "explicit HtmlHelpers for rendering partials" feature, which by default is switched off. I am using T4MVC version 2.6.40.

I recently upgraded to MVC3 and noticed that no explicit HtmlHelpers are generated for Razor partials, so I looked at the source code of the T4MVC text template and found a method named "GetPartials" which has a line of code as folows:

var parts = GetControllers()
        .Select(m => m.ViewsFolder)
        .SelectMany(m => m.Views)
        .Where(m => m.Value.EndsWith(".ascx"));

So it is clear that Razor views are not supported.

I'd also like to mention that when running the T4 template (right-click > run custom tool) I get a compiler warning stating: "The C# 2.0 and C# 3.5 compilers are no longer supported. Templates will always be compiled with the version 4 compiler instead of 'v3.5' as specified."

This relates to line 18 where the template language attribute has a value of "C#v3.5". Why does it have to have an explicit version dependency? Can it not just be "C#"?

Apologies for asking two seperate questions in one post.

I just released T4MVC 2.6.42 to address this. You can get it from Codeplex or from NuGet.

Note that in order to have a razor file be detected as a partial by T4MVC, its name needs to start with an underscore (e.g. _foo.cshtml). Without this restriction, we would end up creating helper methods for all views, which would pollute things and not add value. Note that prefixing partial Razor views with _ is generally recommended by the MVC team.

As for the warning, it's unrelated and is benign. To get rid of it, just change language="C#v3.5" to language="C#". I can't make that change in the official version as that would make it break when running on 3.5 (and I don't want to maintain two separate versions just for that).

When should I use a CompiledQuery?

7 votes

I have a table:

-- Tag

ID  | Name
-----------
1   | c#
2   | linq
3   | entity-framework

I have a class that will have the following methods:

IEnumerable<Tag> GetAll();
IEnumerable<Tag> GetByName();

Should I use a compiled query in this case?

static readonly Func<Entities, IEnumerable<Tag>> AllTags =
    CompiledQuery.Compile<Entities, IEnumerable<Tag>>
    (
        e => e.Tags
    );

Then my GetByName method would be:

IEnumerable<Tag> GetByName(string name)
{
    using (var db = new Entities())
    {
        return AllTags(db).Where(t => t.Name.Contains(name)).ToList();
    }
}

Which generates a SELECT ID, Name FROM Tag and execute Where on the code. Or should I avoid CompiledQuery in this case?

Basically I want to know when I should use compiled queries. Also, on a website they are compiled only once for the entire application?

Compiled queries save you time, which would be spent generating expression trees. If the query is used often, and you'll save the compiled query - then you should definetely use it. I had many cases, when the query parsing took more time, than the actual round trip to the database.

In your case, if you are sure, that it would generate SELECT ID, Name FROM Tag, without the WHERE case (which I doubt, as your AllQueries func should return IQuerieble and the actual query should be made only after calling "ToList") - you shouldn't use it, as someone already mentioned on bigger tables SELECT * FROM [someBigTable] would take very long, and you'll spend even more time filtering that on the client side. So you should make sure, that your filtering is made on the database side, no matter if you are using compiled queries or not.

How many times does a compiled query have to recompile during the lifecycle of an application?

7 votes

In a website, if I have a class:

public class Provider
{
    static readonly Func<Entities, IEnumerable<Tag>> AllTags =
        CompiledQuery.Compile<Entities, IEnumerable<Tag>>
        (
            e => e.Tags
        );

    public IEnumerable<Tag> GetAll()
    {
        using (var db = new Entities())
        {
            return AllTags(db).ToList();
        }
    }
}

In a page I have:

protected void Page_Load(object sender, EventArgs ev)
{
    (new Provider()).GetAll();
}

How many times the query will be compiled? Every time the page loads...? Once in the application...?

Seeing it is compiled. I would say once. Why would it need to be recompiled? Isn't that the point of compiled queries?

Given the compiled query is static, once per application instance/lifetime. Note: Lifetimes may overlap.

In ASP.NET what is the name for HTML directive symbols <%# or <%= etc for executing code on the server side?

7 votes

Was trying to reference this the other day, and I've heard them called several things.

They are intrinsically hard to google for. Does this syntax have a proper name? Thanks!

The Visual Web Developer Team calls them "Code Nuggets," but I don't think there's an official term that'll help you find them in MSDN.

You might be interested in the following MSDN articles:

C# is there a nicer way of writing this?

7 votes
int uploadsID;
int pageNumber;
int x;
int y;
int w;
int h;

bool isValidUploadID = int.TryParse(context.Request.QueryString["uploadID"], out uploadsID);
bool isValidPage = int.TryParse(context.Request.QueryString["page"], out pageNumber);
bool isValidX = int.TryParse(context.Request.QueryString["x"], out x);
bool isValidY = int.TryParse(context.Request.QueryString["y"], out y);
bool isValidW = int.TryParse(context.Request.QueryString["w"], out w);
bool isValidH = int.TryParse(context.Request.QueryString["h"], out h);

if (isValidUploadID && isValidPage && isValidX && isValidY & isValidW & isValidH)
{

This is an ajax handler, checking all passed params are OK. Is this considered bad, and is there a better way to write this, or is it not that important?

Assuming you're not going to use the individual bool variables elsewhere, you could write that as:

int uploadsID, pageNumber, x, y, w, h;
if (int.TryParse(context.Request.QueryString["uploadID"], out uploadsID) &&
    int.TryParse(context.Request.QueryString["page"], out pageNumber) &&
    int.TryParse(context.Request.QueryString["x"], out x) &&
    int.TryParse(context.Request.QueryString["y"], out y) &&
    int.TryParse(context.Request.QueryString["w"], out w) &&
    int.TryParse(context.Request.QueryString["h"], out h))
{
}

You may want to extract out int.TryParse(context.Request.QueryString[name], out variable into a separate method, leaving you with something like:

int uploadsID, pageNumber, x, y, w, h;
if (TryParseContextInt32("uploadID", out uploadsID) &&
    TryParseContextInt32("page", out pageNumber) &&
    TryParseContextInt32("x", out x) &&
    TryParseContextInt32("y", out y) &&
    TryParseContextInt32("w", out w) &&
    TryParseContextInt32("h", out h))
{
}

Alternatively, you could encapsulate all this context data into a new type with a TryParse method, so you'd have something like:

PageDetails details;
if (PageDetails.TryParse(context.Request.QueryString))
{
    // Now access details.Page, details.UploadID etc
}

That's obviously more work, but I think it would make the code cleaner.

Disabled radio button losing value after postback

7 votes

I have two radio buttons that are disabled with javascript when the page loads. RadioButton1 is checked by default. When I click the button to do a postback, the RadioButton1 is no longer checked.

Anyone know why ?

Here's my code sample. The code behind is empty.

<asp:RadioButton ID="RadioButton1" runat="server"  GroupName="group" Checked="true"/>
<asp:RadioButton ID="RadioButton2" runat="server" GroupName="group" />
<asp:Button ID="Button1" runat="server" Text="Button"></asp:Button>
<script type="text/javascript">
    window.onload = function () {
        var RadioButton1 = document.getElementById('<%= RadioButton1.ClientID %>');
        var RadioButton2 = document.getElementById('<%= RadioButton2.ClientID %>');

        RadioButton1.disabled = true;
        RadioButton2.disabled = true;
    };
</script>

This is behavior of HTML, not ASP.NET. Once you mark input element as disabled it is no longer posted in request. For text fields this can be avoided by using Readonly insted of Disabled byt I think it doesn't work for checkboxes or radio buttons. If you want to still post the value you must send it in hidden field related to the radio button and process it manually on the server.

Edit:

Here you can read about disabled and readonly elements and about form submission:

Disabled control:

Disabled control cannot be sucessful.

Read-only control:

Read-only elements may be successful.

Form submission:

A successful control is valid for submission. Every successful control has its control name paired with its current value as part of submitted form data set. A successful control must be defined within a form element and must have a control name.

However:

  • Controls that are disabled cannot be successful.

Strategies for localizing large amounts of text in .NET applications

7 votes

I'm working on an fairly large ASP application that will be fully localized. I'm using the standard named resx approach in satellite assemblies, with fallbacks (that is, es-MX, es-CL and fallback common to es and so on).

Not only will there be probably hundreds (if not a thousand or more!) of different strings; in some places the amount of text that needs to be stored as resource can be long, to the tune of a few paragraphs.

I'm guessing it will be a royal pain to manage these strings in the Visual Studio editor, not to mention the fact that the people who will do some of the translations won't have access to VS in the first place.

How do you folks that work on localized apps manage this type of thing? Any advice and pointers would be appreciated.

If you decide to go DB, check out this article: Creating a Data Driven ASP.NET Localization Resource Provider and Editor by Rick Strahl and then download it for free

If you decide to still using resx, you can use Zeta Resource Editor to mitigate the pain.

How To Do a Server To Server File Transfer without any user interaction?

6 votes

In my scenario, users are able to upload zip files to a.example.com

I would love to create a "daemon" which in specified time intervals will move-transfer any zip files uploaded by the users from a.example.com to b.example.com

From the info i gathered so far,

  1. The daemon will be an .ashx generic handler.
  2. The daemon will be triggered at the specified time intervals via a plesk cron job
  3. The daemon (thanks to SLaks) will consist of two FtpWebRequest's (One for reading and one for writing).

So the question is how could i implement step 3?

  • Do i have to read into to a memory() array the whole file and try to write that in b.example.com ?
  • How could i write the info i read to b.example.com?
  • Could i perform reading and writing of the file at the same time?

No i am not asking for the full code, i just can figure out, how could i perform reading and writing on the fly, without user interaction.

I mean i could download the file locally from a.example.com and upload it at b.example.com but that is not the point.

To answer your questions - yes you can read and write the files at the same time.

You can open an FTPWebRequest to ServerA and a FTPWebRequest to ServerB. On the FTPWebRequest to serverA you would request the file, and get the ResponseStream. Once you have the ResponseStream, you would read a chunk of bytes at a time, and write that chunck of bytes to the serverB RequestStream.

The only memory you would be using would be the byte[] buffer in your read/write loop. Just keep in mind though that the underlying implementation of FTPWebRequest will download the complete FTP file before returning the response stream.

Similarly, you cannot send your FTPWebRequest to upload the new file until all bytes have been written. In effect, the operations will happen synchronously. You will call GetResponse which won't return until the full file is available, and only then can you 'upload' the new file.

References:

FTPWebRequest

Stubbing ASP.NET Page.Form for unit tests

6 votes

Fo unit testing ASP.NET controls I need a stubbed Page.

I can create an ASP.NET Page object in my unit tests by subclassing System.Web.UI.Page. However, I cannot find a way to set Page.Form. Adding a form with attribute (runat,server) does not work. Overloading the form in my Subclass does not give the required functionality.

Context: I try to unit test some homemade ASP.NET controls. These control require Page and Page.Form not to be null.

Any suggestions?

Try defining an IPage and IForm interface that implement the needed methods and properties and create classes that implements those interfaces and wraps a Page or Form class. This way you can test the logic in those controls, without calling into the ASP.NET framework during unit testing.

UPDATE:

Overriding the page property will be brittle and is not advisable. Instead, you should try to minimize the amount of untestable code, by extracting logic in methods that don't depend on any ASP.NET specific (hard to test) parts. Take a look at the following example:

public class MyLabel : Label
{
    protected override override void RenderContents(HtmlTextWriter writer)
    {
        IPage page = new PageWrapper(this.Page);
        this.MethodToTest(page);

        base.RenderContents(writer);
    }

    internal void MethodToTest(IPage page)
    {
        // Work with IPage interface.
        if (page.IsPostBack)
        {
            this.Text = string.Empty;
        }
    }
}

By extracting the logic out of methods that are hard to test, you can call those extracted methods directly in your tests. For instance:

[TestMethod]
public void MethodToTest_ScenarioToTest_ExpectedBehavior()
{
    // Arrange
    var label = new MyLabel();

    var page = new TestPage()
    {
        IsPostBack = true
    };

    // Act
    label.MethodToTest(page);

    // Assert
    Assert.IsTrue(string.Empty, label.Text);
}

It would be even better if you would be able to extract the code under test to it's own class and call it from your WebControl. This is however, not always possible.

I hope this makes sense.

MVC site search functionality

6 votes

i need a simple site search functionality for my mvc app. some of the pages are static and some dynamic (like news articles that are entered in cms). I would like the search to handle both. is this product any good? http://www.sitesearchasp.net any other?

@stephbu - Thank you for the mention.

If you choose to use arachnode.net, you have the choice of either Lucene.NET or SQL Full-text Indexing.

There are some 'head-scratchers' with Lucene.NET, especially when establishing concurrent read/write/search scenarios, but as a static reflection of content it works very well.

If you want something that is free, and turn-key, try Solr(.Net) or Microsoft Search Server.

http://www.microsoft.com/enterprisesearch/en/us/search-server-express.aspx (this was free last I looked at it...)

Thanks! Mike

jQuery Infinite Scroll and Gridview

6 votes

suppose i have 10,000 records in database but i want to show 100 record in the page through gridview and i want when user scroll down and reach the last record in the page then rest of the 100 record will load in the gridview through jquery. in this way data will load when user scroll down. so i have some question in my mind like.

1) how to detect that user reach at the last record when i am showing 100 record when page loads.

2) if i could detect then i can initiate JQuery ajax call to fetch next 100 record and append the new 100 records again at the bottom gridview. so how i can assign data or append data into gridview by jquery.

please discuss in detail...sample code will be more helpful. thanks

I have done it this way with MVC 2 and jQuery:

Controller:

/// <summary>
/// GET: /Widget/Search/
/// Displays search results.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public ActionResult Search(SearchType searchType, string s, [DefaultValue(1)]int page)
{
    try
    {
        int batch = 20;
        int fromRecord = 1;
        int toRecord = batch;

        if(page != 1)
        {
            toRecord = (batch * page);
            fromRecord = (toRecord - (batch-1));

        }

        var widgets= _repos.Search(searchType, s, fromRecord, toRecord );

        if (widgets.Count == 0)
        {
            InfoMsg("No widgets were found.");
        }

        if (Request.IsAjaxRequest())
        {        
            if(widgets.Count > 0)
            {
                return View("SearchResultsLineItems", widgets);
            }
            else
            {
                return new ContentResult
                {
                    ContentType = "text/html",
                    Content = "noresults",
                    ContentEncoding = System.Text.Encoding.UTF8
                };
            }

        }

        return View("SearchResults", widgets);
    }
    catch (Exception ex)
    {
        return HandleError(ex);
    }
}

View:

 <% if (Model.Count > 0) { %>  
    <table id="tblSearchResults">
        <tr>
            <th></th>
            <th>Col1</th>
            <th>Col2</th>
            <th>Col3</th>
            <th>Col4</th>
            <th>Col5</th>
            <th>Col6</th>
        </tr>
        <% Html.RenderPartial("SearchResultsLineItems", Model); %>       
    </table>
    <div id="loadingSearchResults" style="text-align:center;height:24px;"></div>    
    <div id="actionModal" class="modal"></div>
    <% } %>

Script:

function initAutoPaging() {
    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - $(window).height()) {
            loadMore()
        }
    });
}


var current = 1;
function loadMore() {
    if (current > -1) {
        if (!_isShowingDetails)
        {
            if (!$('#loadingSearchResults').html()) {
                current++;
                $('#loadingSearchResults').show();
                $('#loadingSearchResults').html("<img src='/content/images/loading.gif' />");
                $.ajax({
                    async: true,
                    url: document.URL + "?&page=" + current,
                    contentType: "application/x-www-form-urlencoded",
                    dataType: "text",
                    success: function(data) {
                    if (data != 'noresults') {                           
                            $('#tblSearchResults tr:last').after(data);
                            $('#loadingSearchResults').hide();
                            $('#loadingSearchResults').html('');
                            highlightSearch();
                        } else {
                            current = -1;
                            $('#loadingSearchResults').show();
                            $('#loadingSearchResults').html("<h3><i>-- No more results -- </i></h3>");
                        }                     
                    }
                });
            }
        }

    }
}

6 votes

I want to load test an ASP.NET web service. I have Visual Studio 2008 Professional Edition and Visual Studio 2010.

Can either one of these products facilitate load testing? I can't seem to find anything and all Google returns is higher end editions of Visual Studio.

If not, what are some of the alternatives.

Or better yet, is there a product where I can feed it an IIS log and it will essentially replay it?

Is there a cheaper way to do load testing than upgrading to Visual Studio 2010 Ultimate
and also there was a tool called "MICROSOFT WEB APPLICATION STRESS TOOL" but i couldnt find its download apperantely MS removed it from its official page. check this forum for download link http://forums.iis.net/t/1161284.aspx for usage http://www.west-wind.com/presentations/webstress/webstress.htm

SessionID changing across different instances in Azure (and probably in a web farm)

6 votes

Hi,

I have a problem with an Azure project with one WebRole but multiple instances that uses cookieless sessions. The application doesn't need Session storage, so it's not using any session storage provider, but I need to track the SessionID. Apparently, the SessionID should be the same accross the WebRole instances, but it changes suddently w/o explanation. We are using the SessionID to track some data, so it's very important.

In order to reproduce the issue:

  1. Create a Cloud Project.

  2. Add a ASP.NET Web Role. The code already in it will do.

  3. Open Default.aspx

  4. Add a control to see the current SessionID and a button to cause a postback

            <p><%= Session.SessionID %></p>
            <asp:Button ID="Button1" runat="server" Text="PostBack" onclick="Button1_Click" />
    
  5. Add a event handler for button that will delay the response a bit:

    protected void Button1_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(150);
    }
    
  6. Open Web.Config

  7. Enable cookieless sessions:

    <system.web>
            <sessionState cookieless="true" />
    </system.web>
    
  8. Run the project, and hit fast and repeteadly the "PostBack" button for a while giving attention to the session id in the address bar. Nothing happens, the session id is always the same :). Stop it.

  9. Open ServiceConfiguration.csfg

  10. Enable four instances:

    <Instances count="4" />
    
  11. Ensure that in the Web.config there is a line related with the machine key that has been added automatically by Visual Studio. (at the end of system.web).

  12. Rerun the project, hit fast and repeteadly the "Postback" button for a while and give attention to the session id in the address bar. You'll see how the SessionID changes after a while.

Why is this happening? As far as I know, if all machines share the machineKey, the session should be the same across them. With cookies there are no problems, the issue apparently is just when cookieless sessions are used.

My best guess, is that something wrong is happening when there are several instances, when the SessionID generated in one WebRole goes to another, is rejected and regenerated. That doesn't make sense, as all the WebRoles have the same machineKey.

In order to find out the problem, and see it more clearly, I created my own SessionIDManager:

public class MySessionIDManager : SessionIDManager
{
    public override string CreateSessionID(HttpContext context)
    {
        if (context.Items.Contains("AspCookielessSession"))
        {
            String formerSessionID = context.Items["AspCookielessSession"].ToString();

           // if (!String.IsNullOrWhiteSpace(formerSessionID) && formerSessionID != base.CreateSessionID(context))
               // Debugger.Break();

            return formerSessionID;
        }
        else
        {
            return base.CreateSessionID(context);
        }
    }
}

And to use it change this line in the WebConfig:

    <sessionState cookieless="true" sessionIDManagerType="WebRole1.MySessionIDManager" />

Now you can see that the SessionID doesn't change, no matter how fast and for how long you hit. If you uncomment those two lines, you will see how ASP.NET is creating a new sessionID even when there is already one.

In order to force ASP.NET to create a new session, just a redirect to an absolute URL in your site:

 Response.Redirect(Request.Url.AbsoluteUri.Replace(Request.Url.AbsolutePath, String.Empty));

Why is this thing happening with cookieless sessions?

How reliable is my solution in MySessionIDManager ?

Kind regards.

UPDATE:

  • I've tried this workaround: User-Specified Machine Keys Overwritten by Site-Level Auto Configuration, but the problem still stands.

    public override bool OnStart()
    {
        // For information on handling configuration changes
        // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
    
        using (var server = new ServerManager())
        {
            try
            {
                // get the site's web configuration
                var siteNameFromServiceModel = "Web"; // update this site name for your site. 
                var siteName =
                    string.Format("{0}_{1}", RoleEnvironment.CurrentRoleInstance.Id, siteNameFromServiceModel);
                var siteConfig = server.Sites[siteName].GetWebConfiguration();
    
                // get the appSettings section
                var appSettings = siteConfig.GetSection("appSettings").GetCollection()
                    .ToDictionary(e => (string)e["key"], e => (string)e["value"]);
    
                // reconfigure the machine key
                var machineKeySection = siteConfig.GetSection("system.web/machineKey");
                machineKeySection.SetAttributeValue("validationKey", appSettings["validationKey"]);
                machineKeySection.SetAttributeValue("validation", appSettings["validation"]);
                machineKeySection.SetAttributeValue("decryptionKey", appSettings["decryptionKey"]);
                machineKeySection.SetAttributeValue("decryption", appSettings["decryption"]);
    
                server.CommitChanges();
                _init = true;
            }
            catch
            {
            }
        }
        return base.OnStart();
    }
    
  • I've also tried this about put a session start handler and add some data, but no luck.

    void Session_Start(object sender, EventArgs e)
    {
        Session.Add("dummyObject", "dummy");
    }
    

Bounty up!

In short, unless you use cookies or a session provider there is no way for the session id to pass from one web role instance to the other. The post you mention says that the SessionID does NOT stay the same across web roles if you don't use cookies or session storage.
Check this previous question for ways to handle state storage in Azure, e.g. using Table Storage

The machineKey has nothing to do with sessions or the application domain, it is the key used to encrypt,decrypt,validate authentication and viewstate data. To verify this open SessionIDManager.CreateSessionID with Reflector. You will see that the ID value is just a random 16-byte value encoded as a string.

The AspCookielessSession value is already checked by SessionIDManager in the GetSessionID method, not CreateSessionID so the check is already finished before your code gets executed. Since the default sessionstate mode is InProc it makes sence that separate web roles will not be able to validate the session key so they create a new one.

In fact, a role may migrate to a different physical machine at any time, in which case its state will be lost. This post from the SQL Azure Team describes a way to use SQL Azure to store state for exactly this reason.

EDIT I finally got TableStorageSessionStateProvider to work in cookieless mode!

While TableStorageSessionStateProvider does support cookieless mode by overriding SessionStateStoreProviderBase.CreateUnititializedItem, it fails to handle empty sessions properly in private SessionStateStoreData GetSession(HttpContext context, string id, out bool locked, out TimeSpan lockAge,out object lockId, out SessionStateActions actions,bool exclusive). The solution is to return an empty SessionStateStoreData if no data is found in the underlying blob storage.

The method is 145 lines long so I won't paste it here. Search for the following code block

if (actions == SessionStateActions.InitializeItem) 
{
     // Return an empty SessionStateStoreData                    
     result = new SessionStateStoreData(new SessionStateItemCollection(),
}

This block returns an empty session data object when a new session is created. Unfortunately the empty data object is not stored to the blob storage.

Replace the first line with the following line to make it return an empty object if the blob is empty:

if (actions == SessionStateActions.InitializeItem || stream.Length==0)

Long stroy short cookieles session state works as long as the provider supports it. You'll have to decide whether using cookieless state justifies using a sample provider though. Perhaps vtortola should check the AppFabric Caching CTP. It includes out-of-the-box ASP.NET providers, is a lot faster and it definitely has better support than the sample providers. There is even a step-by-step tutorial on how to set session state up with it.

SecurityElement.IsValidText returns true on "&" ... why?

5 votes

I have a TextBox that is eventually saved in a xml node. I am using the SecurityElement.Escape(string2Escape) to escape the invalid characters before saving the xml.

Problem: I tried using the IsValidText to test if i need to run the escape method, but it returns ''' and '&' as valid but then when you save the xml the system barfs because they are, in fact, not valid. It seems to only return false on '<' or '>'.

Simple solution, remove the check, but my question is why would this be the case?

The following is my failing code:

private string EscapeXML(string nodeText)
{
    if (!SecurityElement.IsValidText(nodeText))
    {
        return SecurityElement.Escape(nodeText);
    }
    return nodeText;
}

The SecurityElement constructor is apparently already doing some escaping on its own (including the "&" character), so the IsValidText seems to be only checking for the characters the constructor is not already taking care of. As a consequence, it doesn't look safe to use the SecurityElement's IsValidText/Escape combo, unless you're using SecurityElement to build the whole xml.

I'll try to explain better with an example:

using System;
using System.Diagnostics;
using System.Security;

class MainClass
{
    public static void Main (string[] args)
    {
        // the SecurityElement constructor escapes the & all by itself 
        var xmlRoot =
            new SecurityElement("test","test &");

        // the & is escaped without SecurityElement.Escape 
        Console.WriteLine (xmlRoot.ToString());

        // this would throw an exception (the SecurityElement constructor
        // apparently can't escape < or >'s
        // var xmlRoot2 =
        //    new SecurityElement("test",@"test & > """);

        // so this text needs to be escaped before construction 
        var xmlRoot3 =
            new SecurityElement("test",EscapeXML(@"test & > """));
        Console.WriteLine (xmlRoot3.ToString());

    }

    private static string EscapeXML(string nodeText)
    {
        return (SecurityElement.IsValidText(nodeText))?
            nodeText :
            SecurityElement.Escape(nodeText);
    }
}