Uploading Files using AJAX

Normally, if you want to to upload files through a website you would use a <form> element with enctype=”multipart/form-data” that posts the file from a nested file-<input> element to the specified action (in ASP.NET MVC you would receive that file on the server side by means of a HttpPostedFileBase variable as argument of your action method).

But if you don’t have or don’t want to use a <form> for some reason you have to find other ways to upload a file.

The obvious way would be to assemble and submit a invisible form with Javascript when the user triggers the upload event. To make this work properly you would also have to create an <iframe> as “target” for the <form> that receives the response. The advantage of this method is that it works with all browsers.

Another approach would be to use AJAX, that is using an XMLHttpRequest object. This is also very simple and done in a few lines of Javascript code:

var xhr = new XMLHttpRequest();
xhr.open("POST", url, true); // method, url, async
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("X-File-Name", file.fileName);
xhr.setRequestHeader("X-File-Size", file.fileSize);
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.send(file);

In the above code the “url” would be the “Controller/Action” to which the Request is posted to and the “file” can be extracted from any file-<input> element.

The “X-File-Name” and “X-File-Size” are just self-chosen optional parameters that will be appended to the RequestHeader. That way you can send additional data with the Request.

Again, the “Content-Type” has the be “multipart/form-data” as we’re sending a file/binary data.

The “Cache-Control” is set to “no-cache”, to bypass server cache, so it cannot respond with a “304 Not Modified” response header and skip sending the data.

Finally, we have to subscribe to the “onreadystatechange” event in order to receive the Response from the server:

...
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {      // completed
        if (xhr.status == 200) {    // OK
            var response = xhr.responseText;
            // do something
        }
    }
}
...

This solution should work quite well. But if you are using jQuery I would recommend you to use its .ajax() function instead. jQuery does several optimizations for different browsers and also takes over error handling.

$.ajax({
    beforeSend: function (xhr) {
        xhr.setRequestHeader("Cache-Control", "no-cache");
        xhr.setRequestHeader("X-File-Name", file.fileName);
        xhr.setRequestHeader("X-File-Size", file.fileSize);
        xhr.setRequestHeader("Content-Type", "multipart/form-data");
    },
    type: 'POST',
    url: url,
    processData: false,
    data: file,
    success: function (data, textStatus, xhr) {
        // do something
    },
    error: function (xhr, textStatus, errorThrown) {
        // do something
    }
});

We’re modifying the XMLHttpRequest to be sent in the “beforeSend” callback and set all needed options.
It’s important to set “processData” to “false”. This will prevent jQuery to transform the data to the default content type “application/x-www-form-urlencoded”.

Server Side:

A server side action method could then look like this:

[HttpPost]
public ActionResult UploadFile()
{
    bool success = false;
    string message = String.Empty;

    // Read custom attributes
    string fileName = Request["HTTP_X_FILE_NAME"];  // notice the "HTTP_" prefix
    string fileSize = Request["HTTP_X_FILE_SIZE"];

    try
    {
        // Read input stream from request
        byte[] buffer = new byte[Request.InputStream.Length];
        int offset = 0;
        int cnt = 0;
        while ((cnt = Request.InputStream.Read(buffer, offset, 10)) > 0)
        {
            offset += cnt;
        }
        // Save file
        using (FileStream fs = new FileStream(@"C:\Path\To\Save\File\" + fileName, FileMode.Create))
        {
            fs.Write(buffer, 0, buffer.Length);
            fs.Flush();
        }
        // Or in one line
        // System.IO.File.WriteAllBytes(@"Path\To\Save\File\" + fileName, buffer);

        success = true;
        message = "Success...";
    }
    catch (Exception)
    {
        success = false;
        message = "Error...";
    }

    // Create JSON Response
    var jsonData = new
    {
        success = success,
        message = message
    };

    return Json(jsonData);
}

Making global resources public

Regarding the previous post you may want to use strings from a global resources .resx file (App_GlobalResources) as error messages or descriptions in your attributes. This won’t work because global resource files are by default marked as internal and so you can’t access them from your controller or your model. Also the little “Access Modifier” dropdown menu in the resource editor is grayed out, so you can’t change the access level without further ado.

However there’s a way to change the access rights without editing the designer file by hand.

You just have to open the file properties of the resource file and change the “Custom Tool” from “GlobalResourceProxyGenerator” to “PublicResXFileCodeGenerator”, which is the default Tool for local resource files. Next you have to change the “Build Action” to “Embedded Resource”. You may also want to assign a proper Custom Tool Namespace like “Resources” in order to access the file properly, but this isn’t necessary.

Now rebuild the project and you should notice that the resource access is now public and you can access its contents from anywhere in your project.

E.g. like that:


[Required(ErrorMessageResourceType = typeof(Resources.Resource1), ErrorMessageResourceName = "Comment_Text")]
public string Myproperty { get; set; }

Localizing DisplayNameAttribute

When trying to put a localized string from a resource file (.resx) into the DisplayName Attribute you will get a the following build error:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

An easy way to solve this is to create your own custom DisplayName Attribute. To do that we will create a new class DisplayNameLocalizedAttribute and derive it from the original DisplayNameAttribute and then override the base DisplayName property to return the resource object we want.


public class DisplayNameLocalizedAttribute : DisplayNameAttribute
{
    private readonly string m_ResourceName;
    private readonly string m_ClassName;
    public DisplayNameLocalizedAttribute(string className, string resourceName)
     {
         m_ResourceName = resourceName;
         m_ClassName = className;
     }

     public override string DisplayName
     {
         get
         {
             // get and return the resource object
             return HttpContext.GetGlobalResourceObject(
                    m_ClassName,
                    m_ResourceName,
                    Thread.CurrentThread.CurrentCulture).ToString();
         }
     }
}

Use:


    [DisplayNameLocalized("MyResource", "MyString")]
    public string MyProperty { get; set; }

As you can see, we are now able to pass in a resource name (className) and a resource key (resourceName) and will get the correct string returned. The same procedure should work with similar Attributes such as the DescriptionAttribute.

Update 1: Another way would be by using reflection.

public class DisplayNameLocalizedAttribute : DisplayNameAttribute
{
    private string _displayName;

    public DisplayNameLocalizedAttribute(string resourceKey, Type resourceType)
    {
        PropertyInfo propInfo = resourceType.GetProperty(resourceKey,
                System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
        _displayName = (string)propInfo.GetValue(propInfo.DeclaringType, null);
    }

    public override string DisplayName
    {
        get
        {
            return _displayName;
        }
    }
}

Use:

[DisplayNameLocalized("MyString", typeof(MyResource))]
public string MyProperty { get; set; }

Update 2: In .NET 4.0 this procedure seems to be obsolete as you can just use the new [Display]-Attribute and specify the “ResourceType” and “Name” Properties:

[Display(ResourceType = typeof(MyResource), Name = "MyString")]
public string MyProperty { get; set; }

Unit testing LINQ to SQL in ASP.NET MVC Web Applications

If you want to unit test LINQ to SQL statements in an ASP.NET MVC application you most likely will get a NullReference Exception that is thrown when trying to instantiate the DataContext. That’s because the standard constructor of the DataContext is trying to get the database connection string from the current .config file.

To solve that problem, without changing the code and specifying the connection string explicitly in the DataContext’ constructor, you just have to add an App.config file to your test project and copy the contents (or at least the configuration -> connection strings section) from the Web.config to it.

Second you have to adjust the AttachDbFilename property in the connection string to point again to your actual .mdf file. Since you cannot use relative paths in the connection string, you have to put in the full path. Here’s an interesting excerpt from MSDN:

When DataDirectory is used, the resulting file path cannot be higher in the directory structure than the directory pointed to by the substitution string. For example, if the fully expanded DataDirectory is C:\AppDirectory\app_data, then the sample connection string shown above works because it is below c:\AppDirectory. However, attempting to specify DataDirectory as |DataDirectory|\..\data will result in an error because \data is not a subdirectory of \AppDirectory.

However we have the option to change where the |DataDirectory| shall point to. So you don’t have to touch the connection string directly. To do that you just have to call the AppDomain.SetData Method in the test project.


AppDomain.CurrentDomain.SetData("DataDirectory", @"C:\Projects\MyProject\MyProject\App_Data");

Hide comments in Visual Studio

How often have I wished that there was an option in Visual Studio to hide the comments in the source code. Comments are great, no doubt. And every programmer should well comment his code. However, sometimes they can be a bit annoying and block the sight on the actual code. Mainly if I want to comprehend or refactor a piece of code, it would be nice to have an option to toggle all comments off, especially when it’s my own code. 😉

In short, I wrote a little Add-In for Visual Studio that does just that. Actually it does not really toggle the comments on and off, in fact it sets the text color equal to the background color. It’s probably not the best solution, but it does serve the purpose for now.

It can be downloaded here.

I didn’t make an installer for the Add-In, so you just have to put the unpacked files into your %VSMYDOCUMENTS%\Addins folder where %VSMYDOCUMENTS% usually points to “C:\Users\<UserName>\Documents\Visual Studio 2008”.

You will then see a new button in context menu:

And in the Tools menu to edit the options:

There you can specify what kind of comments should be affected.

Making an asynchronous WebRequest

When downloading large amounts of data a normal synchronous web request, as described in the previous article, may block your current thread. The solution for this is to make an asynchronous web request. To start an asynchronous webrequest WebRequest.BeginGetResponse() has to be called. But before we can do that, we have to write some decent lines of code.

At first we have to create an object that stores the state of the request. To do this we create a new class RequestState:


public class RequestState
{
    public int BufferSize { get; private set; }
    public StringBuilder ResponseContent { get; set; }
    public byte[] BufferRead { get; set; }
    public HttpWebRequest Request { get; set; }
    public HttpWebResponse Response { get; set; }
    public Stream ResponseStream { get; set; }

    public RequestState()
    {
        BufferSize = 1024;
        BufferRead = new byte[BufferSize];
        ResponseContent = new StringBuilder();
        Request = null;
        ResponseStream = null;
    }
}

After that we need to create a Callback method to process the response. This has to be in the form of the AsyncCallback delegate:


    public delegate void AsyncCallback(IAsyncResult ar);

So here’s our method:


private void ResponseCallback(IAsyncResult result)
{
    try
    {
        // Get and fill the RequestState
        RequestState state = (RequestState)result.AsyncState;
        HttpWebRequest request = state.Request;
        // End the Asynchronous response and get the actual resonse object
        state.Response = (HttpWebResponse)request.EndGetResponse(result);
        Stream responseStream = state.Response.GetResponseStream();
        state.ResponseStream = responseStream;

        // Begin async reading of the contents
        IAsyncResult readResult = responseStream.BeginRead(state.BufferRead,
                0, state.BufferSize, new AsyncCallback(ReadCallback), state);
    }
    catch (Exception ex)
    {
        // Error handling
        RequestState state = (RequestState)result.AsyncState;
        if (state.Response != null)
            state.Response.Close();
    }
}

As you can see, we need another Callback method for our asynchronous read operation. We also just could call the responseStream.ReadToEnd() method to get the response data but that would again block the calling thread. So the response should also be read asynchonously.


private void ReadCallback(IAsyncResult result)
{
    try
    {
        // Get RequestState
        RequestState state = (RequestState)result.AsyncState;
        // determine how many bytes have been read
        int bytesRead = state.ResponseStream.EndRead(result);

        if (bytesRead > 0) // stream has not reached the end yet
        {
            // append the read data to the ResponseContent and...
            state.ResponseContent.Append(Encoding.ASCII.GetString(state.BufferRead, 0, bytesRead));
            // ...read the next piece of data from the stream
            state.ResponseStream.BeginRead(state.BufferRead, 0, state.BufferSize,
                new AsyncCallback(ReadCallback), state);
        }
        else // end of the stream reached
        {
            if (state.ResponseContent.Length > 0)
            {
                // do something with the response content, e.g. fill a property or fire an event
                AsyncResponseContent = state.ResponseContent.ToString();
                // close the stream and the response
                state.ResponseStream.Close();
                state.Response.Close();
                OnAsyncResponseArrived(AsyncResponseContent);
            }
        }
    }
    catch (Exception ex)
    {
        // Error handling
        RequestState state = (RequestState)result.AsyncState;
        if (state.Response != null)
            state.Response.Close();
    }
}

Now that we have written all this code, we are finally ready to call WebRequest.BeginGetResponse() and pass in an instance of the RequestState class and the ResponseCallback:


public void MakeWebRequestAsync(string url)
{
    try
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "GET";
        request.Proxy = null;

        RequestState state = new RequestState();
        state.Request = request;

        IAsyncResult result = request.BeginGetResponse(new AsyncCallback(ResponseCallback), state);
    }
    catch (Exception ex)
    {
        // Error handling
    }
}

Implementing a timeout functionality

When making an asynchronous webrequest the WebRequest.Timeout property will be ignored. So we have to implement our own timeout machanism. The following lines will demonstrate how to accomplish that task.

First we need to register a timeout delegate after the request.BeginGetResponse() call:

public void MakeWebRequestAsync(string url, int timeOut)
{
    try
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "GET";
        request.Proxy = null;

        RequestState state = new RequestState();
        state.Request = request;

        IAsyncResult result = request.BeginGetResponse(new AsyncCallback(ResponseCallback), state);

        // Timeout comes here
        ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle,
            new WaitOrTimerCallback(TimeOutCallback), request, timeOut, true);
    }
    catch (Exception ex)
    {
        // Error handling
    }
}

In the TimeOutCallback we’re just aborting the webrequest. It looks something like this:


private void TimeOutCallback(object state, bool timedOut)
{
    if (timedOut)
    {
        HttpWebRequest request = state as HttpWebRequest;
        if (request != null)
            request.Abort();
    }
}
public class RequestState { public int BufferSize { get; private set; } public StringBuilder ResponseContent { get; set; } public byte[] BufferRead { get; set; } public HttpWebRequest Request { get; set; } public HttpWebResponse Response { get; set; } public Stream ResponseStream { get; set; }   public RequestState() { BufferSize = 1024; BufferRead = new byte[BufferSize]; ResponseContent = new StringBuilder(); Request = null; ResponseStream = null; } }

WebRequest slow?

I recently tried to do a web request in .NET C#. So I looked it up in the MSDN and wrote down some lines of code and was happy that it worked  straightaway (ok, it’s not very complex anyhow).

It looked something like this:

    string responseContent;
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "GET";

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    Stream responseStream = response.GetResponseStream();
    using (StreamReader sr = new StreamReader(responseStream))
        responseContent = sr.ReadToEnd();

    return responseContent;

But this code was very slow and it took several seconds to get the response.
One reason for that is that if you don’t use a proxy or just don’t set the proxy property of the WebRequest, it tries to auto-detect and configure a proxy what causes a significant delay.
So just adding

    request.Proxy = null;

before the GetResponse() call will fix that problem.

Remark/Update: To be more correct, you should set “request.Proxy = GlobalProxySelection.GetEmptyWebProxy();” instead of just null. (MSDN: HttpWebRequest.Proxy property)

Another point is that you should always close the WebResponse after processing its contents. That might also speed up your requests. I prefer to use “using” statements to do that. It will get a bit nested sometimes but this way you just can’t forget it.
So here’s the final code for a simple “GET” request:

public string MakeWebRequest(string url)
{
    try
    {
        string responseContent;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "GET";
        request.Proxy = GlobalProxySelection.GetEmptyWebProxy(); // null;

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader sr = new StreamReader(responseStream))
                    responseContent = sr.ReadToEnd();
            }
        }

        return responseContent;
    }
    catch (Exception ex)
    {
        // Error handling
        return ex.Message;
    }
}

Extending the code for a “POST” request:

To make a “POST” request we have to add the following:

public string MakeWebRequest(string url, string postData)
{
    try
    {
        string responseContent;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        // Set Method to "POST"
        request.Method = "POST";
        // Convert "POST" data to a byte array
        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        // Set the content type of the WebRequest
        request.ContentType = "application/x-www-form-urlencoded";
        // Set the content length
        request.ContentLength = byteArray.Length;
        // Get the request stream
        using (Stream requestStream = request.GetRequestStream())
        {
            // Write the "POST" data to the stream
            requestStream.Write(byteArray, 0, byteArray.Length);
        }
        // Don't forget to set the proxy
        request.Proxy = GlobalProxySelection.GetEmptyWebProxy(); // null;

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader sr = new StreamReader(responseStream))
                    responseContent = sr.ReadToEnd();
            }
        }

        return responseContent;
    }
    catch (Exception ex)
    {
        // Error handling
        return ex.Message;
    }
}
public string MakeWebRequest(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = “GET”;
request.Proxy = null;

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Stream responseStream = response.GetResponseStream();
using (StreamReader sr = new StreamReader(responseStream))
{
string responseContent = sr.ReadToEnd();
return responseContent;
}
}
}
catch (Exception ex)
{
return ex.Message;
}
}

%d bloggers like this: