Best asp.net questions in December 2010

Is there any benefit to using SecureString in ASP.NET?

13 votes

If I understand correctly, this is for keeping plain text out of memory, so that the app is secure against esoteric attacks on memory, the garbage heap, or memory paged to disk. The SecureString is fed unmanaged bytes and consumed one unmanaged byte at at time--then the string is erased from memory. (Correct me if I way off!)

In ASP.NET, the secret is collected in a webform, which post back in HTTPS. But then the Request object turns all the request values from the form into name value pairs and puts them in a collection, e.g. Request["TxtPassword"]-- so even before I can get the string, it's already been written insecurely to memory. Worse, if I was using a control, then the unsecure representation will have more managed strings in the property of the TextBox.

To do anything with this SecureString I need an API that takes unmanaged strings--so it seems I can't use the secure string for a stored proc parameter or much else.

Am I doing this wrong or is it a fool's errand to try to use SecureString and not leak copies of the unsecured string into managed memory?

Switching to OAuth or Windows auth isn't an option.

As you correctly deduced, and others already mentioned, it makes little sense to use SecureString to store security-sensitive data that comes from an ASP.NET form, because that data is already present in memory in an insecure form.

There are other scenarios, however, where the use of SecureString is recommended, because the sensitive data is created by the program itself and shouldn't remain in memory after it's done working with it. For instance, creating a SharePoint site programmatically, or transferring authentication credentials from one system to another.

Back in the good old days, it was easier to ensure that the lifetime of sensitive data was as short as possible. It could be allocated on the stack and cleared as soon as the program was done using it:

char secret[512];
generate_secret(secret, sizeof(secret));
do_something_with(secret);
memset(secret, 0, sizeof(secret));
// Secret data is now gone.

Such an approach is not possible with managed strings, though, mainly because:

  • They're not allocated on the stack,
  • They're immutable, so they can't be cleared,
  • They're not disposable, so there's no guarantee about the time when the GC will free the data. It might even never be freed, depending on memory conditions.

SecureString tries to solve that problem by being mutable and disposable, which allows one to do:

using (SecureString secret = new SecureString()) {
    GenerateSecret(secret);
    secret.MakeReadOnly();
    DoSomethingWith(secret);
}
// Secret data is now gone.

How do I stream .flv files from SQL database

9 votes

I want to store .flv files in the database and not in the file system.

This is what I can do right now:
Successfully convert .wmv and .mpeg to .flv with ffmpeg.
Store images in SQL Server and show them on my page with an httphandler.
Same with .avi and .mpeg videos. (It's up to the user's software if he can view it though)
Play .flv files in the browser if the file is located in the file system and not in the database.

What I can't do is:
Stream .flv videos to JW Player directly from the database. (Stored as binary data)

I've searched the internet for two days now but I can't get it to work. It feels as if I'm almost there though. The JW Player opens up and starts to "buffer", but nothing happens.

I know there's no easy answer but if anyone has done this before, or something similar, I'd like to know how you did. I feel I've got too much code to post it all here.

Thanks in advance!

/zalk

EDIT: Solved!
Posted it as an answer instead...

I got it to work but I have no idea as to how efficient it is. Is it better to stream from the file system than from the database in terms of connections, efficency, load etc. I could use some pointers on this!

I'm using JW Player here, hence "swfobject.js" and "player.swf"

httpHandler:

public class ViewFilm : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        try
        {
            // Check if id was given
            if (context.Request.QueryString["id"] != null)
            {
                string movId = context.Request.QueryString["id"];

                // Connect to DB and get the item id
                using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
                using (SqlCommand cmd = new SqlCommand("GetItem", con))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    SqlParameter sqlParam = cmd.Parameters.Add("@itemId", SqlDbType.Int);
                    sqlParam.Value = movId;

                    con.Open();
                    using (SqlDataReader dr = cmd.ExecuteReader())
                    {
                        if (dr.HasRows)
                        {
                            dr.Read();
                            // Add HTTP header stuff: cache, content type and length
                            context.Response.Cache.SetCacheability(HttpCacheability.Public);
                            context.Response.Cache.SetLastModified(DateTime.Now);
                            context.Response.AppendHeader("Content-Type", "video/x-flv");
                            context.Response.AppendHeader("Content-Length", ((byte[])dr["data"]).Length.ToString());
                            context.Response.BinaryWrite((byte[])dr["data"]);
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

javascript
The function adds a player to <div id="video1"> and can be called e.g when a user clicks a button.

<script type='text/javascript' src='swfobject.js'></script>
<script type="text/javascript" language="javascript">
function vid() {
  var s1 = new SWFObject('player.swf', 'player1', '480', '270', '9');
  s1.addParam('allowfullscreen', 'true');
  s1.addParam('allowscriptaccess', 'always');
  s1.addVariable('file', encodeURIComponent('ViewFilm.ashx?id=10'));
  s1.addVariable('type', 'video');
  s1.write(document.getElementById("video1"));
}
</script>

ASP.NET MVC - Posting a form with custom fields of different data types

8 votes

In my ASP.NET MVC 2 web application, I allow users to create custom input fields of different data types to extend our basic input form. While tricky, building the input form from a collection of custom fields is straight-forward enough.

However, I'm now to the point where I want to handle the posting of this form and I'm not certain what the best way to handle this would be. Normally, we'd use strongly-typed input models that get bound from the various statically-typed inputs available on the form. However, I'm at a loss for how to do this with a variable number of input fields that represent different data types.

A representative input form might look something like:

  • My date field: [ date time input control ]
  • My text field: [ text input field ]
  • My file field: [ file upload control ]
  • My number field: [ numerical input control ]
  • My text field 2: [text input field ]
  • etc...

Ideas I've thought about are:

  • Sending everything as strings (except for the file inputs, which would need to be handled specially).
  • Using a model with an "object" property and attempting to bind to that (if this is even possible).
  • Sending a json request to my controller with the data encoded properly and attempting to parse that.
  • Manually processing the form collection in my controller post action - certainly an option, but I'd love to avoid this.

Has anyone tackled an issue like this before? If so, how did you solve it?

Update:

My "base" form is handled on another input area all together, so a solution doesn't need to account for any sort of inheritence magic for this. I'm just interested in handling the custom fields on this interface, not my "base" ones.

Update 2:

Thank you to ARM and smartcaveman; both of you provided good guidance for how this could be done. I will update this question with my final solution once its been implemented.

This is how I would begin to approach the issue. A custom model binder would be pretty easy to build based on the FormKey property (which could be determined by the index and/or label, depending).

public class CustomFormModel
{
    public string FormId { get; set; }
    public string Label { get; set; }
    public CustomFieldModel[] Fields { get; set; }
}
public class CustomFieldModel
{
    public DataType DateType { get; set; } //  System.ComponentModel.DataAnnotations
    public string FormKey { get; set; }
    public string Label { get; set; }
    public object Value { get; set; }
}
public class CustomFieldModel<T> : CustomFieldModel
{
    public new T Value { get; set; }
}

Also, I noticed one of the comments below had a filtered model binder system. Jimmy Bogard from Automapper made a really helpful post about this method at http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/03/17/a-better-model-binder.aspx , and later revised in, http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/11/19/a-better-model-binder-addendum.aspx . It has been very helpful for me in building custom model binders.

Update

I realized that I misinterpreted the question, and that he was specifically asking how to handle posting of the form "with a variable number of input fields that represent different data types". I think the best way to do this is to use a structure similar to above but leverage the Composite Pattern. Basically, you will need to create an interface like IFormComponent and implement it for each datatype that would be represented. I wrote and commented an example interface to help explain how this would be accomplished:

public interface IFormComponent
{
    //  the id on the html form field.  In the case of a composite Id, that doesn't have a corresponding 
    //  field you should still use something consistent, since it will be helpful for model binding
    //  (For example, a CompositeDateField appearing as the third field in the form should have an id 
    //  something like "frmId_3_date" and its child fields would be "frmId_3_date_day", "frmId_3_date_month",
    //  and "frmId_3_date_year".
    string FieldId { get; }

    //  the human readable field label
    string Label { get; }

    //  some functionality may require knowledge of the 
    //  Parent component.  For example, a DayField with a value of "30"
    //  would need to ask its Parent, a CompositeDateField
    //  for its MonthField's value in order to validate
    //  that the month is not "February"
    IFormComponent Parent { get; }

    //  Gets any child components or null if the 
    //  component is a leaf component (has no children).
    IList<IFormComponent> GetChildren();

    //  For leaf components, this method should accept the AttemptedValue from the value provider
    //  during Model Binding, and create the appropriate value.  
    //  For composites, the input should be delimited in someway, and this method should parse the 
    //  string to create the child components.  
    void BindTo(string value);

    //  This method should parse the Children or Underlying value to the 
    //  default used by your business models.  (e.g. a CompositeDateField would 
    //  return a DateTime.  You can get type safety by creating a FormComponent<TValue>
    //  which would help to avoid issues in binding.
    object GetValue();

    //  This method would render the field to the http response stream.
    //  This makes it easy to render the forms simply by looping through 
    //  the array.  Implementations could extend this for using an injected 
    //  formatting 
    void Render(TextWriter writer);
} 

I am assuming that the custom forms can be accessed via some sort of id which can be contained as a form parameter. With that assumption, the model binder and provider could look something like this.

public interface IForm : IFormComponent
{
    Guid FormId { get; }
    void Add(IFormComponent component);
}
public interface IFormRepository
{
    IForm GetForm(Guid id);
}
public class CustomFormModelBinder : IModelBinder   
{
    private readonly IFormRepository _repository;
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        ValueProviderResult result;
        if(bindingContext.ValueProvider.TryGetValue("_customFormId", out result))
        {
            var form = _repository.GetForm(new Guid(result.AttemptedValue));
            var fields = form.GetChildren();
            //  loop through the fields and bind their values 
            return form;
        }
        throw new Exception("Form ID not found.");
    }
}

Obviously, all the code here is just to get the point across, and would need to be completed and cleaned up for actual use. Also, even if completed this would only bind to an implementation of the IForm interface, not a strongly typed business object. (It wouldn't be a huge step to convert it to a dictionary and build a strongly typed proxy using the Castle DictionaryAdapter, but since your users are dynamically creating the forms on the site, there is probably no strongly typed model in your solution and this is irrelevant). Hope this helps more.

Change Enter from submission to Tab?

8 votes

Users don't like the fact that the Enter key submits the page. So I am tasked with preventing the submission and changing the Enter key to a Tab to the next field.

I have tried many javascript snippets found on the net but none have worked so far. The only one that has even come close to having an effect was e.preventDefault() of the jQuery API, which stops the submit, but nothing I have tried emulates the tab behavior.

e.returnValue = false;
e.cancel = true;

Page still submits with the above in the keydown event handler. Same effect with return false in the keydown event handler. The handler is firing, tested by putting a breakpoint in it with firebug.

This needs to work with both IE and Firefox.

Don't say "don't do this".
1) I'm already convinced that I shouldn't do it, but it's not a choice that is mine, so the discussion is mute.
2) It would be an answer to the question "Should I do this?", which is not the question that I am asking.

This just feels icky, but you could use event.preventDefault as you mentioned and then call focus() on the next closest input:

Here's a simple example:

$("input").bind("keydown", function(event) {
    if (event.which === 13) {
        event.stopPropagation();
        event.preventDefault();
        $(this).next("input").focus();
    }
});

Example: http://jsfiddle.net/andrewwhitaker/Txg65/

Update: If you have elements in between your inputs, using plain next() will not work. Instead, use nextAll():

$("input").bind("keydown", function(event) {
    if (event.which === 13) {
        event.stopPropagation();
        event.preventDefault();
        $(this).nextAll("input").eq(0).focus();
    }
});

http://jsfiddle.net/andrewwhitaker/GRtQY/

Razor: @Html.Partial() vs @RenderPage()

8 votes

What is the appropriate way of rendering a child template?

And what's the difference? Both seem to work for me.

And why does @Html.RenderPartial() no longer work?

Html.Partial uses the MVC Html Helper whereas RenderPage is a Web Pages thing. It comes from WebPageRenderingBase. Ultimately it's a matter of taste. Some people can't get over the fact that MVC is dependent on ASP.NET Web Pages (the foundation of WebMatrix), and would prefer not to be reminded of that when they look at their View code.

OptimisticConcurrencyException Does Not Work in Entity Framework In Certain Situations

7 votes

UPDATE (2010-12-21): Completely rewrote this question based on tests that I've been doing. Also, this used to be a POCO specific question, but it turns out that my question isn't necessarily POCO specific.

I'm using Entity Framework and I've got a timestamp column in my database table that should be used to track changes for optimistic concurrency. I've set the concurrency mode for this property in the Entity Designer to "Fixed" and I'm getting inconsistent results. Here are a couple of simplified scenarios that demonstrate that concurrency checking works in one scenario but not in another.

Successfully throws OptimisticConcurrencyException:

If I attach a disconnected entity, then SaveChanges will throw an OptimisticConcurrencyException if there is a timestamp conflict:

    [HttpPost]
    public ActionResult Index(Person person) {
        _context.People.Attach(person);
        var state = _context.ObjectStateManager.GetObjectStateEntry(person);
        state.ChangeState(System.Data.EntityState.Modified);
        _context.SaveChanges();
        return RedirectToAction("Index");
    }

Does not throw OptimisticConcurrencyException:

On the other hand, if I retrieve a new copy of my entity from the database and I do a partial update on some fields, and then call SaveChanges(), then even though there is a timestamp conflict, I don't get an OptimisticConcurrencyException:

    [HttpPost]
    public ActionResult Index(Person person) {
        var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
        currentPerson.Name = person.Name;

        // currentPerson.VerColm == [0,0,0,0,0,0,15,167]
        // person.VerColm == [0,0,0,0,0,0,15,166]
        currentPerson.VerColm = person.VerColm;

        // in POCO, currentPerson.VerColm == [0,0,0,0,0,0,15,166]
        // in non-POCO, currentPerson.VerColm doesn't change and is still [0,0,0,0,0,0,15,167]
        _context.SaveChanges();
        return RedirectToAction("Index");
    }

Based on SQL Profiler, it looks like Entity Framework is ignoring the new VerColm (which is the timestamp property) and instead using the originally loaded VerColm. Because of this, it will never throw an OptimisticConcurrencyException.


UPDATE: Adding additional info per Jan's request:

Note that I also added comments to the above code to coincide with what I see in my controller action while working through this example.

This is the value of the VerColm in my DataBase prior to the update: 0x0000000000000FA7

Here is what SQL Profiler shows when doing the update:

exec sp_executesql N'update [dbo].[People]
set [Name] = @0
where (([Id] = @1) and ([VerColm] = @2))
select [VerColm]
from [dbo].[People]
where @@ROWCOUNT > 0 and [Id] = @1',N'@0 nvarchar(50),@1 int,@2 binary(8)',@0=N'hello',@1=1,@2=0x0000000000000FA7

Note that @2 should have been 0x0000000000000FA6, but it's 0x0000000000000FA7

Here is the VerColm in my DataBase after the update: 0x0000000000000FA8


Does anyone know how I can work around this problem? I'd like Entity Framework to throw an exception when I update an existing entity and there's a timestamp conflict.

Thanks

Explanation

The reason why you aren't getting the expected OptimisticConcurrencyException on your second code example is due to the manner EF checks concurrency:

When you retrieve entities by querying your db, EF remembers the value of all with ConcurrencyMode.Fixed marked properties by the time of querying as the original, unmodified values.

Then you change some properties (including the Fixed marked ones) and call SaveChanges() on your DataContext.

EF checks for concurrent updates by comparing the current values of all Fixed marked db columns with the original, unmodified values of the Fixed marked properties. The key point here is that EF treats the update of you timestamp property as a normal data property update. The behavior you see is by design.

Solution/Workaround

To workaround you have the following options:

  1. Use your first approach: Don't requery the db for your entity but Attach the recreated entity to your context.

  2. Fake your timestamp value to be the current db value, so that the EF concurrency check uses your supplied value like shown below (see also this answer on a similar question):

    var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
    currentPerson.VerColm = person.VerColm; // set timestamp value
    var ose = _context.ObjectStateManager.GetObjectStateEntry(currentPerson);
    ose.AcceptChanges();       // pretend object is unchanged
    currentPerson.Name = person.Name; // assign other data properties
    _context.SaveChanges();
    
  3. You can check for concurrency yourself by comparing your timestamp value to the requeried timestamp value:

    var currentPerson = _context.People.Where(x => x.Id == person.Id).First();
    if (currentPerson.VerColm != person.VerColm)
    {
        throw new OptimisticConcurrencyException();
    }
    currentPerson.Name = person.Name; // assign other data properties
    _context.SaveChanges();
    

Find the right parameters for an event without using Design Mode in Visual Studio 2010

6 votes

Is there a way to know what parameters are needed by an event in Visual Studio 2010?

Let's say I have a DropDownList control and I want to bind a method to the "OnSelectedIndexChanged", I would do something like this

In the ASPX File:

<asp:DropDownList ID="lstMyList" runat="server" OnSelectedIndexChanged="lstMyList_SelectedIndexChanged"></asp:DropDownList>

In the codebehind:

protected void lstMyList_SelectedIndexChanged(object sender, EventArgs e) 
{
    ...
}

Is there a way to know what parameters the method needs? (In this case, an object for the sender and an EventArgs parameter for the event.)

I know you can easily create the method by double-clicking the right event in Design Mode, but it does a mess with your code so I prefer not to use it.

Thanks!

You can find out the parameters by "going to definition" (F12) on the appropriate event, finding out what delegate type it uses, then going to definition on that. In this case the SelectedIndexChanged event has type EventHandler which is defined as follows:

[SerializableAttribute]
[ComVisibleAttribute(true)]
public delegate void EventHandler(
    Object sender,
    EventArgs e
)

You can also find this information by searching the web or pressing F1 and searching in the help.


I know you can easily create the method by double-clicking the right event in Design Mode, but it does a mess with your code so I prefer not to use it.

I think you should try to overcome your fear of using the designer. You are most likely wasting more time in lost productivity by not using the code generation features in Visual Studio than the potential time you might have saved by protecting yourself against the designer messing up your code.

ASP.NET Web Application (MVC) Deployment Automation and Subversion

6 votes

We are trying to automate the build process to our staging servers but have run into a snag, albeit fairly minor. We are using the Publish functionality built into VS2010, committing to Subversion, and then a 3rd party app (Beanstalk) automatically pulls the updated files and FTPs them to the Staging server.

The problem we've run into is that we only appear to have the following choices:

  • (Lesser of 2 evils) If we choose to use "Replace matching files with local copies", this works great, with one exception: this option does not delete any files that were deleted from the project. This will lead to junk and/or security issues for unkempt files from the days of old.
  • If we choose to use "Delete all existing files prior to publish", this deletes the entire folder structure, including the .SVN hidden folders that Subversion uses for Update tracking, etc. This seems like the best solution from an accuracy standpoint, but it really destroys the local SVN environment, which is the middle-man for this automation.

My question: Is there an easy work around for this, or a totally different deployment option we're overlooking (we do not want to publish directly to the server from VS, as we want to track who/what/when a deployment takes place)? The only thing I've come across is to delete the file contents manually prior to publishing, while leaving the folder structure intact, then deploying with "Replace matching files with local copies". Unfortunately, this brings on a whole new meaning of the word "automation".

Any ideas on how best to accomplish this?

You may want to consider using NAnt or something similar for tasks you wish to automate, like building and publishing to Subversion. This is most of my build file for a WebApplication Project. It might be different for MVC. If so, I'm sure you can use this as a starting point. I am by no means an NAnt expert so there may be some flaws, but this is definitely working for me.

I had to add a PublishToFileSystem target to each .csproj file I wanted to publish. The source for that can be found here.

Build file also available on Pastebin

<?xml version="1.0"?>
<project name="deploy" default="all">
    <property name="nant.settings.currentframework" value="net-4.0" />  
    <!-- Any of these can be passed through the command line -->
    <property name="sourceDirectory" value="${project::get-base-directory()}" />
    <property name="publishDirectory" value="${sourceDirectory}\build" />
    <property name="MSBuildPath" value="${framework::get-assembly-directory(framework::get-target-framework())}\msbuild.exe" />
    <!-- The build configuration to use when publishing and transforming the web.config file. This is useful when you have multiple environments for which you create builds -->
    <property name="buildConfiguration" value="Release" /> 
    <!-- Set these as needed -->
    <property name="svn.username" value="" />
    <property name="svn.password" value="" />

    <target name="SvnPrep">
        <property name="svn.dir" value="${publishDirectory}\.svn" />
        <property name="svn.update" value="true" readonly="false" />
        <echo>env.svn.path = svn</echo>
        <echo>svn.dir = ${svn.dir}</echo>
        <mkdir dir="${publishDirectory}" unless="${directory::exists(publishDirectory)}" />
        <!-- Check if there's a .svn dir already. If not: checkout, else: update. -->
        <if test="${not directory::exists(svn.dir)}">
            <exec program='svn.exe' workingdir="${publishDirectory}" verbose="true">
                <arg line='co ${svn.builduri} --username ${svn.username} --password ${svn.password} --non-interactive ./' />
            </exec>
            <property name="svn.update" value="false" readonly="false" />
        </if>
        <if test="${svn.update}">
            <exec program='svn.exe' workingdir="${publishDirectory}\" verbose="true">
                <arg line='up --username ${svn.username} --password ${svn.password} --non-interactive --force ./' />
            </exec>
        </if>
        <!-- Force any conflicts to be resolved with the most recent code -->
        <exec program='svn.exe' workingdir="${publishDirectory}\" verbose="true">
            <arg line='resolve --accept theirs-full -R ./' />
        </exec>
    </target>   

    <target name="DeleteFiles">
        <!-- Delete only the files (retain directory structure) in the directory to which you are going to publish/build. NAnt excludes svn directories by default. -->
        <delete includeemptydirs="false">
            <fileset basedir="${publishDirectory}">
                <include name="**/*.*" /> 
            </fileset>
        </delete>
    </target>
    <target name="Publish">
        <!-- I know there's an MSBuild task, I don't know why I didn't use it, but this works. -->
        <!-- Build and publish frontend -->
        <exec program="${MSBuildPath}">
            <arg line='"${sourceDirectory}\YourProject.csproj"' />
            <arg value='"/p:Platform=AnyCPU;Configuration=${buildConfiguration};PublishDestination=${publishDirectory}"' />
            <arg value="/target:PublishToFileSystem" />
        </exec>
        <!-- Transform the correct web.config and copy it to the build folder. PublishToFileSystem doesn't transform the web.config, unfortunately. -->
        <exec program="${MSBuildPath}">
            <arg line='"${sourceDirectory}\YourProject.csproj"' />
            <arg value='"/p:Platform=AnyCPU;Configuration=${buildConfiguration};PublishDestination=${publishDirectory}"' />
            <arg value="/target:TransformWebConfig" />
        </exec>
        <copy file="${sourceDirectory}\YourProject\obj\${buildConfiguration}\TransformWebConfig\transformed\Web.config" tofile="${publishDirectory}\YourProject\web.config" overwrite="true" />     
    </target>

    <target name="SvnCommit">       
        <!-- add any new files -->
        <exec program='svn.exe' workingdir="${publishDirectory}" verbose="true">
            <arg line='add --force .' />
        </exec>
        <!-- delete any missing files, a modification of this http://stackoverflow.com/questions/1071857/how-do-i-svn-add-all-unversioned-files-to-svn -->
        <!-- When there's nothing to delete it looks like this fails (to NAnt) but it is actually fine, that's why failonerror is false -->     
        <exec program='cmd.exe' workingdir="${publishDirectory}\" verbose="true" failonerror="false" 
            commandline='/C for /f "usebackq tokens=2*" %i in (`svn status ^| findstr /r "^\!"`) do svn del "%i %j"' >
        </exec>
        <exec program='svn.exe' workingdir="${publishDirectory}" verbose="true">
            <arg line='commit -m "Automated commit from build runner"' />
        </exec>
    </target>

    <target name="ShowProperties">
        <script language="C#" prefix="util" >
            <code>
                <![CDATA[
                public static void ScriptMain(Project project) 
                {
                    foreach (DictionaryEntry entry in project.Properties)
                    {
                        Console.WriteLine("{0}={1}", entry.Key, entry.Value);
                    }
                }
                ]]>
            </code>
        </script>
    </target>

    <target name="all">
        <call target="ShowProperties" />
        <call target="SvnPrep" />
        <call target="DeleteFiles" />
        <call target="Publish" />
        <call target="SvnCommit" />
    </target>
</project>

using Plupload with ASP.NET/C#

5 votes

UPDATE

I was able to get everything to work properly and I just wanted to post back with the updated code. I used Darin Dimitrov's suggestion on using a separate generic http handler for handling the file uploads and so this is the code I came up with for that... let me know if you have questions.

<%@ WebHandler Language="C#" Class="Upload" %>

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Net;
using System.Web;

public class Upload : IHttpHandler {

    public void ProcessRequest(HttpContext context) {

        /**
         * If 'newTicket' is "false", then the directory to upload to already exists and we can extract it from
         * the 'ticketID' POST parameter.
         * 
         * If 'newTicket' is "true", then this is a new Ticket submission so we need to work with a NEW directory 
         * on the server, so the ID needs to be 1 more than the total number of directories in ~/TicketUploads/
         */
        String newTicket = context.Request["newTicket"] != null ? context.Request["newTicket"] : String.Empty;
        int theID = -1;
        if (newTicket.Equals("true")) {

            // we need to calculate a new ID
            theID = getNewID(context); // calculate the new ID = # of rows
            theID++; // add 1 to make it unique
        } else if (newTicket.Equals("false")) {

            // we can just get the ID from the POST parameter
            theID = context.Request["ticketID"] != null ? Convert.ToInt32(context.Request["ticketID"]) : -1;
        } else {

            // something went wrong with the 'newTicket' POST parameter
            context.Response.ContentType = "text/plain";
            context.Response.Write("Error with 'newTicket' POST parameter.");
        }

        // if theID is negative, something went wrong... can't continue
        if (theID < 0) {
            return;
        }

        // ready to read the files being uploaded and upload them to the correct directory
        int chunk = context.Request["chunk"] != null ? int.Parse(context.Request["chunk"]) : 0;
        string fileName = context.Request["name"] != null ? context.Request["name"] : string.Empty;
        var uploadPath = context.Server.MapPath("~/TicketUploads/" + theID + "/");
        HttpPostedFile fileUpload = context.Request.Files[0];

        // if the NEW directory doesn't exist, create it
        DirectoryInfo di = new DirectoryInfo("" + uploadPath + "");
        if (!(di.Exists)) {
            di.Create();
        }

        using (var fs = new FileStream(Path.Combine(uploadPath, fileName), chunk == 0 ? FileMode.Create : FileMode.Append)) {
            var buffer = new byte[fileUpload.InputStream.Length];
            fileUpload.InputStream.Read(buffer, 0, buffer.Length);
            fs.Write(buffer, 0, buffer.Length);
        }

        context.Response.ContentType = "text/plain";
        context.Response.Write("File uploaded.");
        return;
    }
}

I'm trying to integrate the Plupload file uploader in ASP.NET using C#. I've read the Angry Monkeys article as well as the Marco Valsecchi blog post but I'm a little lost.

The C# that the above articles suggest is roughly similar to the following:

int chunk = Request.QueryString["chunk"] != null ? int.Parse(Request.QueryString["chunk"]) : 0;
string fileName = Request.QueryString["name"] != null ? Request.QueryString["name"] : string.Empty;

HttpPostedFile fileUpload = Request.Files[0];

using (FileStream fs = new FileStream(Server.MapPath("~/TicketUploads/" + fileName), chunk == 0 ? FileMode.Create : FileMode.Append))
{
    Byte[] buffer = new Byte[fileUpload.InputStream.Length];
    fileUpload.InputStream.Read(buffer, 0, buffer.Length);

    fs.Write(buffer, 0, buffer.Length);
    fs.Close();
}

First, I have set up the Plupload configuration as follows:

$("#plupload_container").pluploadQueue({
  runtimes: 'html5,gears,flash,silverlight,html4',
  flash_swf_url: '../plupload/js/plupload.flash.swf',
  silverlight_xap_url: '../plupload/js/plupload.silverlight.xap',
  filters: [
    { title: "Image files", extensions: "jpg,gif" },
    { title: "Zip files", extensions: "zip" },
    { title: "Document files", extensions: "doc,pdf,txt" }
  ]
});

... but I feel like I'm missing something here that will be necessary for the uploading to work.

I guess my main question is how do I call the above C# code so that the uploading can begin? I have a form on a page named SubmitRequest.aspx. Clicking 'Submit' on the form results in the following:

$('form').submit(function (e) {

  // Validate number of uploaded files
  if (uploader.total.uploaded == 0) {
    // Files in queue upload them first
    if (uploader.files.length > 0) {
      // When all files are uploaded submit form
      uploader.bind('UploadProgress', function () {
        if (uploader.total.uploaded == uploader.files.length)
          $('form').submit();
      });
      uploader.start();
    }
    e.preventDefault();
  }
});

... so the uploader starts when 'Submit' is clicked and uploads the files. Once that is done, the rest of the form is submitted. I don't understand how to link this event to the C# code that will handle the uploading to a folder TicketUploads on the server.

I apologize for the longish post, but I would appreciate any help :)

Thanks, Hristo

Here's a full working example I wrote for you:

<%@ Page Title="Home Page" Language="C#" %>
<%@ Import Namespace="System.IO" %>
<script runat="server" type="text/c#">
    protected void Page_Load(object sender, EventArgs e)
    {
        // Check to see whether there are uploaded files to process them
        if (Request.Files.Count > 0)
        {
            int chunk = Request["chunk"] != null ? int.Parse(Request["chunk"]) : 0;
            string fileName = Request["name"] != null ? Request["name"] : string.Empty;

            HttpPostedFile fileUpload = Request.Files[0];

            var uploadPath = Server.MapPath("~/TicketUploads");
            using (var fs = new FileStream(Path.Combine(uploadPath, fileName), chunk == 0 ? FileMode.Create : FileMode.Append))
            {
                var buffer = new byte[fileUpload.InputStream.Length];
                fileUpload.InputStream.Read(buffer, 0, buffer.Length);

                fs.Write(buffer, 0, buffer.Length);
            }
        }
    }
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head id="Head1" runat="server">
    <title></title>

    <style type="text/css">@import url(css/plupload.queue.css);</style>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
        google.load("jquery", "1.3");
    </script>
    <script type="text/javascript" src="/plupload/js/gears_init.js"></script>
    <script type="text/javascript" src="http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script>
    <script type="text/javascript" src="/plupload/js/plupload.full.min.js"></script>
    <script type="text/javascript" src="/plupload/js/jquery.plupload.queue.min.js"></script>
    <script type="text/javascript">
    $(function() {
        $("#uploader").pluploadQueue({
            // General settings
            runtimes : 'gears,flash,silverlight,browserplus,html5',
            url : '/default.aspx',
            max_file_size : '10mb',
            chunk_size : '1mb',
            unique_names : true,
            // Resize images on clientside if we can
            resize : {width : 320, height : 240, quality : 90},
            // Specify what files to browse for
            filters : [
                {title : "Image files", extensions : "jpg,gif,png"},
                {title : "Zip files", extensions : "zip"}
            ],
            // Flash settings
            flash_swf_url : '/plupload/js/plupload.flash.swf',
            // Silverlight settings
            silverlight_xap_url : '/plupload/js/plupload.silverlight.xap'
        });

        // Client side form validation
        $('form').submit(function(e) {
            var uploader = $('#uploader').pluploadQueue();
            // Validate number of uploaded files
            if (uploader.total.uploaded == 0) {
                // Files in queue upload them first
                if (uploader.files.length > 0) {
                    // When all files are uploaded submit form
                    uploader.bind('UploadProgress', function() {
                        if (uploader.total.uploaded == uploader.files.length)
                            $('form').submit();
                    });
                    uploader.start();
                } else
                    alert('You must at least upload one file.');
                e.preventDefault();
            }
        });
    });
    </script>

</head>
<body>
    <form id="Form1" runat="server">
        <div id="uploader">
            <p>You browser doesn't have Flash, Silverlight, Gears, BrowserPlus or HTML5 support.</p>
        </div>
    </form>
</body>
</html>

As you will see in this example files are uploaded to the same page called default.aspx. Notice that parameters such as chunk and name are POSTed so you shouldn't use Request.QueryString to read them but Request["chunk"] directly as this will look at the POST body as well. You should also make sure that the TicketUploads folder exists on the server at the root.

In this example the same page default.aspx is used for showing the upload form and handling the uploads. In a real world application this is not something I would do. I would recommend you using a separate script which will handle the file uploads such as a generic http handler (upload.ashx).

Finally you will notice that I have used some default settings that you might wish to modify and reconfigure the plugin to fit your needs. I just took the settings from the documentation.


UPDATE:

And since I recommended using a separate generic http handler for handling the file uploads here's how it might look :

using System.IO;
using System.Web;

public class Upload : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        int chunk = context.Request["chunk"] != null ? int.Parse(context.Request["chunk"]) : 0;
        string fileName = context.Request["name"] != null ? context.Request["name"] : string.Empty;

        HttpPostedFile fileUpload = context.Request.Files[0];

        var uploadPath = context.Server.MapPath("~/TicketUploads");
        using (var fs = new FileStream(Path.Combine(uploadPath, fileName), chunk == 0 ? FileMode.Create : FileMode.Append))
        {
            var buffer = new byte[fileUpload.InputStream.Length];
            fileUpload.InputStream.Read(buffer, 0, buffer.Length);

            fs.Write(buffer, 0, buffer.Length);
        }

        context.Response.ContentType = "text/plain";
        context.Response.Write("Success");
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

Now all that's left is to reconfigure the plugin to point to this generic handler:

...
runtimes: 'gears,flash,silverlight,browserplus,html5',
url: '/upload.ashx',
max_file_size: '10mb',
...

How do I programmatically upload pictures to facebook?

5 votes

Ok, so here was my first question: How do I allow visitors on my site to share my photos on their facebook news feed?

After implementing it I realized what I really want is to upload the image as a photo to their photo album.

How would I got about getting an image on my site, to upload to their photo album, when they click on a facebook icon next to the image?

Any thoughts at all are appreciated.

Thank You.

Register your application at Facebook (create a Facebook app).

Authenticate the user with Facebook, at the same time user approves your app access.

Use Facebook publishing api to upload image (follow link, look for Publishing title).

asp.net mvc validation must be a number custom error

5 votes

Hi,

I am new to asp.net and I have a problem. When the users insert in a editor for a decimal field something other than numbers, they get an error "Field name" is not a number. But I don't want them to receive this message I want them to receive another message. I have no problem with this with required and range validators. Is there any way for me to do this?

I am not refering necessarily to changing the culture just displaying another message.

Thanks.

This is the actual answer:

create a class CustomClientDataTypeModelValidatorProvider copy the code from the MVC sources change the method MakeErrorString to output the appropiate message like this:

private static string MakeErrorString(string displayName)
            {
                return String.Format(CultureInfo.CurrentCulture, Core.Resources.Errors.EroareNuENr, displayName);
            }

I couldn't find a way not to copy the code just extend it as it uses this static method. If anyone knows this please tell me.

The in global asax I wrote this:

var cdProvider = ModelValidatorProviders.Providers.SingleOrDefault(p => p.GetType().Equals(typeof(ClientDataTypeModelValidatorProvider)));
            if(cdProvider != null)
            {
                ModelValidatorProviders.Providers.Remove(cdProvider);
                ModelValidatorProviders.Providers.Add(
                        new CustomClientDataTypeModelValidatorProvider());
            }

so that the flow would actually be routed to my class and not the class in the asp.net MVC dll

I got the idea from here:

Do I need to care about thread-safety in ASP.NET with AJAX?

4 votes

The question is, is it possible that requests for the same session are executed from multiple threads? Are methods in ASP.NET reentrant? Especially we are using AJAX which means that asychronous requests are taking place.

Would this mean to place locks around operations on objects placed inside the session?

I know that locks are essential when handling static and application wide variables, but the question is is the same true for session objects?

ASP.NET normally uses one thread per request. It can use more than one thread, e.g. when serving asynchronous pages, but even then only one thread will be processing the request at any given time.

It's safe to use the session state from multiple threads, however, because accesses to the session object are serialized. From MSDN:

What if other pages attempt to concurrently access the session state? In that case, the current request might end up working on inconsistent data, or data that isn't up to date. Just to avoid this, the session state module implements a reader/writer locking mechanism and queues the access to state values. A page that has session-state write access will hold a writer lock on the session until the request terminates.