Best asp.net questions in November 2011

Release Management - releasing to a subset of users - how would it work for a public facing website

17 votes

I read somewhere (sorry don't exactly remember the source) that facebook has release Tuesdays. They release the new features to their internal employees first, then to a small set of external users and then to the whole world. I believe google also does something similar

I work primarily with Microsoft stack (TFS for source control, IIS, asp.net, sql server with huge data). Public facing sites of course, so they have to be up 24x7x365. Though I can envision releasing my api/dll only on one of the servers (in the webfarm) and testing it out, how would I do this if there are DB (stored proc signatures, table schema changes )? Presently we are versioning SPs (the new ones will be mySPNameV2, where as the old one will be mySPNameV1 - both taking different set of parameters hence the renaming) and the new APIs would use SP-V2 where as the old API would continue with SP-V1.

I see some design smell, but is there a better way to do it?

Edit: we release the new code to only one server and test it, what is difficult is how would you abstract (may be abstract is not the right word, but you get the idea) db schema changes from multiple concurrent versions of the application

If I understood you correctly, what you want is to have two mechanisms that use the same live data, but different API versions. Now, assuming you're already working with a double buffer mechanism, I guess that your actual problem is to use live tables during that transition.

The solution is for your tables to include both V1 and V2 columns (e.g., one users table that will include fields from both APIs). Note: All non-common fields must have default values.

In order for this to work seamlessly, you should create views for V1 and V2, exposing only the relevant fields for each API version, and you should develop for views instead of tables (similar to the concept of developing for interfaces instead of implementation).

The same goes for stored procedures - all non-common parameters must have default values, etc...

Linq-to-SQL and DateTime weirdness

13 votes

We have really strange and inconsistent behavior with Linq-to-SQL here.

Our app is installed at quite a few customer's sites, and works just fine for the most part. One of the queries in Linq-to-SQL updates a table and set a DateTime column to a new value.

In all the cases - including our dev and test systems - this Linq-to-SQL statement gets translated into something along the lines of:

UPDATE dbo.OurTable SET WorkTimeStamp = @WTS WHERE ID = @ID
   @WTS = '2011-11-04 14:15:25', @ID = 555

However, at one customer's site, for reasons that aren't clear to us (yet), this update gets translated into:

UPDATE dbo.OurTable SET WorkTimeStamp = @WTS WHERE ID = @ID
   @WTS = 'Nov  4 2011 02:15:25PM', @ID = 555

and for some reason then fails on SQL Server 2005.

Now, that customer's servers (web server and SQL Server) have US-English versions of Windows Server 2008 installed; the language in SQL Server is set to us_english, the date format is set to mdy, the user account running the update has its language set to English in SQL Server ..... and that setup is the same elsewhere (e.g. on our test server infrastructure).

So my question really is:

  1. Why on earth does Linq-to-SQL suddenly create a totally different representation of the same DateTime to send to SQL Server? Is there any knob to turn to control this??

  2. And why can't ADO.NET and the SQL Server 2005 SP2 database handle that UPDATE statement correctly? We're getting an error in our log that reads:

SqlTypeException - SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

Seems to be a .NET error (more than a SQL Server error) and it seems as if .NET cannot really interpret that Nov 4 2011 02:15:25PM as a valid DateTime for some reason. When attempting to run the generated UPDATE statement in SQL Server Management Studio, we cannot seem to "force" that error to happen - the UPDATE happily works just fine.....

?????

Any ideas?

Update: some further investigation seems to indicate Linq-to-SQL behaves differently when going against SQL Server 2005 or 2008.

  • with SQL Server 2005, our dates get turned into: Nov 4 2011 02:15:25PM
  • with SQL Server 2008, our dates get turned into: 2011-11-04 02:15:25PM

I think you might the chasing the wrong problem.

I would first check:

  1. Your Linq2Sql schema/database model is accurate.
  2. Your problem logic to make sure there is no way the new DateTime value can be out of range. In particular, check that it can not be either DateTime.MinValue or DateTime.MaxValue.
  3. That you aren't doing any string to date parsing in your application.
  4. That the Sql server does not have any triggers (particularly instead of triggers, which might be modifying the update statement).

I am guessing you (or your customer) starting by getting the 'SqlTypeException - SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM' error message and upon investigating you noticed the difference in the way that the dates are displayed

You don't mention where the the info is coming from, so I assuming something like SQL profiler.

However the date display issue may be a red-herring as it should not be a problem.

with SQL Server 2005, our dates get turned into: Nov 4 2011 02:15:25PM

with SQL Server 2008, our dates get turned into: 2011-11-04 02:15:25PM

I'm not sure exactly what you mean by that. SQL does not 'turn' dates into string as it does not store dates as string, but the internal representation is a number (something like the number of days since 1st Jan 1900)

If you mean your dates get displayed as Nov 4 2011 02:15:25PM, then that is up to the program that is displaying the information.

Also, as I understand it, if you are using a DateTime parameter (which Linq2Sql should be doing if the database model is accurate), then the information that is sent from the client to the SQL Server is the SQL numeric representation of the DateTime. This should avoid any datetime conversion issues between the client and server. When you look at, for example, SQL Profiler, it does not show you the numeric representation of the date, which will mean very little to most people, but tries to be helpful and displays the value as a string.

The important point is that if sql or sql profiler manages to display a datetime parameter as 'Nov 4 2011 02:15:25PM' then it knows it is a valid date and it knows exactly what date that is.

So I would suspect that the display format issue is probably irrelevant.

That then leaves the question as to why your customer is getting the SqlTypeException - SqlDateTime overflow error message.

The first thing to do is to check what date value you are setting, which needs to be done at the application level and not at the SQL server since it would not get that far. (This is another reason why I don't think this is a SQL configuration issue)

it seems as if .NET cannot really interpret that Nov 4 2011 02:15:25PM as a valid DateTime for some reason

I don't see where .Net would be even trying to interpret strings as date unless you have some DateTime.Parse commands and if that is the case, then the problem has nothing to do with either LINQ or SQL.

Problems reading cookies in Sharepoint with anonymous access

7 votes

I save a cookie in a sharepoint webpart in this way:

System.Web.HttpCookie cookie = new System.Web.HttpCookie(_cookieApplicationId);
cookie[_cookieName] = value;
cookie.Expires = DateTime.Now.AddMonths(1);
HttpContext.Current.Response.SetCookie(cookie);

That cookie is always saved successfully. I can see it on the client using firebug. When I try to read that cookie:

System.Web.HttpCookie cookie = HttpContext.Current.Request.Cookies[_cookieApplicationId];
return cookie[_cookieName];

It DOES work when I am signed in, but it does not if I am not logged in.

Saving always works no matter if I am logged in or not. So where is the error?

After days of trial and error and testing it seemed to be a caching issue from one (or multiple) of these participants: [Sharepoint, IIS, browser]

Adding

HttpContext.Current.Response.Cache.SetNoServerCaching();
HttpContext.Current.Response.Cache.SetNoStore();

solved the problem. I just don't know why caching is different in anonymous access

ASP.NET MVC3 - what do you do with probing requests?

6 votes

our site went online and of course, we started to receive loads of probing requests, like

'/blog/wp-login.php'
'/admin/admin.php'

etc.
So question is, what do you do with them?

Right now in each case 404 error is thrown and elmah sends email about it, but I think it would be better to ignore at least all php requests at all.

How to do that, that such requests would minimally load server, may be it is possible to do, that asp.net pipeline would be not involved in such requests?
Or is it better to redirect, or return empty result?

If that would require simply add IgnoreRoutes, may be someone has good set of routes, that would ignore most of the probing requests?

I know that you have stated the you don't want to use the rewrite module in IIS as it 'adds additional load on IIS', but in truth, using IIS to handle these will be less intensive than passing into your application to do the same thing (even though both are extremely small resource-wise). If you want to ignore the request with the minimal amount of load on IIS and your bandwidth, I would suggest the following

<rewrite>
  <rules>
    <rule name="Fail PHP requests">
      <match url=".*"/>
      <conditions>
        <add input="{URL}" pattern="*.php*" />
      </conditions>
      <action type="AbortRequest" />
    </rule>
   </rules>
</rewrite>

This rewrite with the action type set to AbortRequest completely severs the HTTP connection and drops the request, no 404 or 403 errors returned. Taken from Learn IIS in the 'Creating an Access Block' section.

EDIT - Since there are concerns from the OP on using the rewrite module and performance, I am going to submit a second option that may still catch .php request without using the rewrite module. IIS7 and above also support Request Filtering and according to Learn IIS, Request filtering is...

The request filtering module runs at the beginning of the request processing pipeline by handling the BeginRequest event. The module evaluates the request metadata, such as headers, the query string, content length, etc, in order to determine whether the request metadata matches any existing filter. If there is a match, the module generates a 404 (File Not Found) response and then shortcuts the remainder of the IIS pipeline

To implement, add the following section to your web.config:

<configuration>
 <system.webServer>
  <security>
   <requestFiltering>
    <fileExtensions allowUnlisted="true" >
     <add fileExtension=".php" allowed="false"/>
    </fileExtensions>
   </requestFiltering>
  </security>
 </system.webServer>
</configuration>

Information from URL Rewrite vs Request Filtering and Using Request Filtering

Resource interpreted as Other but transferred with MIME type undefined. error for IE (Asp.net Website)

6 votes

enter image description here

WHen I try to download from Chrome it works fine, but in IE 8 it is not downloading it is showing the error above,

    protected void btn_ExcelDownload_Click(object sender, EventArgs e)
{
    Grid_UserTable.Columns[0].Visible = false;
    string subject = lbl_Subj.Text;
    Response.Buffer = true;
    Response.Clear();
    Response.ClearHeaders();
    Response.AddHeader("Cache-Control", "no-store, no-cache");
    Response.AddHeader("content-disposition", "attachment;filename=" + subject + "-Status.xls");
    Response.Charset = "";
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.ContentType = "application/vnd.ms-excel";
    System.IO.StringWriter stringWrite = new System.IO.StringWriter();
    System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
    Grid_UserTable.RenderControl(htmlWrite);
    rptList.RenderControl(htmlWrite);
    Response.Write(stringWrite.ToString());     
    Response.End();
}

When I used developer tool in chrome it gave Resource interpreted as Other but transferred with MIME type undefined. error but downloaded the file, but IE is throwing the error shown in the image, what should i do, thanks.

I am able to download the file in IE8 when I run the website using Visual studio, but when I try to download it from the website which is uploaded in server I am getting the above error,, The error is only in IE 8.

I tried changing the IE browser Compatibility mode on and off, even then I receive same error.

This is my head content

<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="Server">
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />

  Response.Cache.SetCacheability(HttpCacheability.NoCache);

Solved by removing this line from the code.

Attaching console to running ASP.NET app

5 votes

Let’s say I have a library, in which I added a few Console.WriteLine(..) statements to help me out during the implementation and see what’s going on when I use the library in a Console App.

Now I want to use the same library in an ASP.NET app. Ideally I would be able to log on to the production webserver, and somehow start a command prompt and attach it to the website and see the messages in real time as they occur. How do I do that?

I'm not sure it works with ASP.Net, but you can use Trace.WriteLine instead of Console.WriteLine and then use DebugView to view the traces as they happen.

When do I use System.Threading.ThreadPool and when do I use one of the many custom thread pools?

5 votes

I'm working on creating an asynch handler for asp.net that will execute a slow stored procedure. I think I understand that to gain additional throughput on a mix load of slow and fast pages, that the slow page needs to be executed on a thread pool separate from the one the ASP.NET uses, otherwise the asynch pattern will cause double the number of scarce threads to be used. (correct me if I'm wrong) So I find

System.Threading.ThreadPool - This looks like it should do the trick, but...

The various tutorials on the net such as this one which uses this custom pool, the one in John Skeet's MiscUtils, and the custom thread pool referenced in this tutorial about async patterns.

System.Threading.ThreadPool has existed since 1.1-- why do people routinely feel the need to write a brand new one? Should I avoid using System.Threading.ThreadPool?

I'm a rank beginner when it comes to threading, so go easy on the undefined jargon.

UPDATE. The stored procedure to be executed will not necessarily be MS-SQL and will not necessarily be able to use a built in asynch method such as BeginExecuteNonQuery().

Here's what I found on the topic. Why you shouldn't use ThreadPool in ASP.NET http://madskristensen.net/post/Done28099t-use-the-ThreadPool-in-ASPNET.aspx. It's quite old but I don't think it has changed that much. Or correct me if I'm wrong.

Using the System.Threading.ThreadPool or a custom delegate and calling its BeginInvoke offer a quick way to fire off worker threads for your application. But unfortunately, they hurt the overall performance of your application since they consume threads from the same pool used by ASP.NET to handle HTTP requests.

Using custom threads with the aid of System.Threading.Thread class should solve the problem as the threads created are not part of your application's pool.

Database schema advice for storing form fields and field values

5 votes

I've been tasked with creating an application that allows users the ability to enter data into a web form that will be saved and then eventually used to populate pdf form fields.

I'm having trouble trying to think of a good way to store the field values in a database as the forms will be dynamic (based on pdf fields).

In the app itself I will pass data around in a hash table (fieldname, fieldvalue) but I don't know the best way to convert the hash to db values.

I'm using MS SQL server 2000 and asp.net webforms. Has anyone worked on something similar?

Have you considered using a document database here? This is just the sort of problem they solve alot better than traditional RDBMS solutions. Personally, I'm a big fan of RavenDb. Another pretty decent option is CouchDb. I'd avoid MongoDb as it really isn't a safe place for data in it's current implementation.

Even if you can't use a document database, you can make SQL pretend to be one by setting up your tables to have some metadata in traditional columns with a payload field that is serialized XML or json. This will let you search on metadata while staying out of EAV-land. EAV-land is a horrible place to be.

UPDATE

I'm not sure if a good guide exists, but the concept is pretty simple. The basic idea is to break out the parts you want to query on into "normal" columns in a table -- this lets you query in standard manners. When you find the record(s) you want, you can then grab the CLOB and deserialize it as appropriate. In your case you would have a table that looked something like:

SurveyAnswers
  Id INT IDENTITY
  FormId INT
  SubmittedBy VARCHAR(255)
  SubmittedAt DATETIME
  FormData TEXT

A few protips:
a) use a text based serialization routine. Gives you a fighting chance to fix data errors and really helps debugging.
b) For SQL 2000, you might want to consider breaking the CLOB (TEXT field holding your payload data) into a separate table. Its been a long time since I used SQL 2000, but my recollection is using TEXT columns did bad things to tables.

What's the difference between declarative and imperative programming?

5 votes

I read the following paragraphs about architecture from Microsoft .Net: Architecting Applications for the Enterprise, by Dino Esposito and Andrea Saltarello:

Whenever you take a declarative approach to coding rather than an imperative approach, you are delegating some responsibilities to some other layer of code—a layer that you don't control entirely. So you're ultimately hoping that the intermediate tool will understand you correctly and won't encounter any trouble of its own along the way. In software development, delegating to a third party makes development faster, but you should guarantee that users get exactly what you want them to.

This doesn't mean that you shouldn't trust Visual Studio 2008 or similar wizard-based products. The point is something else entirely. In a large system, likely being developed by several teams, classic declarative programming just doesn't work. You need to have in your presentation a layer of code that decides what to display, where to read settings, and how to apply them. Declarative programming is still a great option, but only if you write the engine and the wizards.

Can someone explain to me in simple words what exactly declarative and imperative programming are?

Declarative programming - What should be done

Imperative programming - How what you want should be done.

Declarative programming requires developers to say what is to be done. Imperative programming requires developers to define step by step how code should be executed.

Example: LINQ in C# is declarative.

Read here for more: http://www.informit.com/articles/article.aspx?p=1330154&seqNum=4

Linq to return records that don't have a follow up record

5 votes

I have this query that counts the total number of +1's a user has made on our website:

return db.tblGPlusOneClicks
    .Where(c => 
        c.UserID == UserID
        && c.IsOn
        )
    .Select(c=>c.URLID)
    .Distinct()
    .Count();

Data originates from this table:

enter image description here

A simple count of distinct URLs where IsOn = true will show the count of pages they have +1'd. However, the table also stores when they un-plus1 something, by storing the value in IsOn as false.

If I:

  • Plus one my homepage
  • Unplus one my homepage

It shouldn't count this as a plus for that user in our query as the last action for this URL for this user was to un-plus 1 it. Similarly, if I:

  • Plus one my homepage
  • Unplus one my homepage
  • Plus one my homepage
  • Unplus one my homepage
  • Plus one my homepage

It should count this in the original query as the last action for that URL was to plus 1 it.

How can I modify my query to count the instances where IsOn is true and that was the last known action for that user for that URL? I'm struggling to write a query that does this.

Try this:

return db.tblGPlusOneClicks
    .Where(c => c.UserID == UserID)
    .GroupBy(c => c.URLID)
    .Count(g => g.OrderByDescending(c => c.Date).First().IsOn);

ASP.NET MVC 3 : Is there a way to get a controller's string Name from its Type?

5 votes

With the UrlHelper in MVC3, you can build a URL for a controller and an action using strings:

@Url.Action("Index", "Somewhere")

Which will route a request to SomewhereController.Index().

What I would like to do, is get a URL to a controller and action, but passing the Type for the controller:

@Url.Action("Index", typeof(SomewhereController))

Is there a way to do this?


Edit / Clarification:

I realize the convention for the Controllers is that the controller name routes to a class named {Name}Controller so I could just remove 'Controller' from the end of my Type.Name. I guess I was assuming that there was a way to override this convention with some custom routing. Though the more I look at it, I'm not sure that is possible...

Maybe MVC3 can only ever route to classes named "*Controller"? I'm combing through the MVC3 source looking for "Controller" hard coded somewhere, but haven't found the answer yet... But if it is possible to route "Somewhere" to the class SomewhereFoo instead of SomewhereController, then just removing "Controller" from the class name would be incorrect.

If someone can give me evidence for or against "Controller" being hard-coded into MVC3 somewhere, then I would feel more comfortable with the "Just remove Controller from the name" approach.

There is no existing extension for this but you could write your own, modeled on the ActionLink from MvcFutures. I suggest a generic method used like @Url.Action<SomewhereController>( c => c.Index )

public static UrlHelperExtensions
{
    public static string Action<TController>( this UrlHelper helper,  Expression<Action<T>> action ) where TController : Controller
    {
        var routeValues = GetRouteValuesFromExpression( action ); 
        return helper.Action( routeValues["action"], routeValues );
    }

    // copied from MvcFutures
    // http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266392
    private static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller
    {
        if (action == null) {
            throw new ArgumentNullException("action");
        }

        MethodCallExpression call = action.Body as MethodCallExpression;
        if (call == null) {
            throw new ArgumentException(MvcResources.ExpressionHelper_MustBeMethodCall, "action");
        }

        string controllerName = typeof(TController).Name;
        if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
            throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
        }
        controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);
        if (controllerName.Length == 0) {
            throw new ArgumentException(MvcResources.ExpressionHelper_CannotRouteToController, "action");
        }

        // TODO: How do we know that this method is even web callable?
        //      For now, we just let the call itself throw an exception.

        var rvd = new RouteValueDictionary();
        rvd.Add("Controller", controllerName);
        rvd.Add("Action", call.Method.Name);
        AddParameterValuesFromExpressionToDictionary(rvd, call);
        return rvd;
    }
}

How to dynamically generate textbox and collect data entered by user?

4 votes

I will appreciate answers in VB or C#

we use a database to create Data Collection forms with dynamic items

enter image description here

I used this code to generate labels and textboxes from a table in database (when the user hits the button "load CRF")

enter image description here

 Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim CRFgrid As New GridView
    CRFgrid.DataSource = CRFds
    CRFgrid.DataBind()

    Dim ItemCount As Integer = CRFgrid.Rows.Count
            Session("Itemcount") = CRFgrid.Rows.Count

    For I = 0 To (ItemCount - 1)
        Dim itemname As String = CRFgrid.Rows(0 + I).Cells(1).Text.ToString
        Session("Item") = "Item" + (I + 1).ToString
        Dim ItemNamelabel As New Label
        Dim ItemNameBox As New TextBox

        ItemNamelabel.ID = "L" + (I + 1).ToString
        Session("FU" + I.ToString) = ItemNamelabel.ID.ToString
        ItemNameBox.ID = "T" + (I + 1).ToString

        ItemNamelabel.Text = "<br />" + (Session("Item").ToString) + " " + itemname + " " + "<br />"

        Me.Form.Controls.Add(ItemNamelabel)
        Me.Form.Controls.Add(ItemNameBox)



    Next
End Sub

when the data collection form is loaded, the page looks like this

enter image description here

and the "view page source" shows

    <!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">
<head><title>

 </title></head>
<body>
<form method="post" action="Default.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"     value="/wEPDwUKLTI0NTA5MDI3NGRkUb8sl0uZpLbvUN/GSmHgjYxS9xqGR7rmcMBR3Ufhz4w=" />
</div>

<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWCQLf7PXOCQKM54rGBgK7q7GGCALF9vKRBQLs7+btDALs7+LtDALs797tDALs79rtDALs79btDDHrb+Vhkcph8brtCJP9//5IH57FFoImey2PApARP+k1" />

<input type="submit" name="Button1" value="LoadCRF" id="Button1" style="width:85px;" />
<br />
<br />
<input type="submit" name="Button2" value="InsertData" id="Button2" style="width:85px;" />
<br />
<br />

MRN
<input name="MRNtxt" type="text" id="MRNtxt" />
<br />
<br />
<span id="L1"><br />Item1 Diagnosis <br /></span><input name="T1" type="text" id="T1" /><span id="L2"><br />Item2 Treatment Protocol <br /></span><input name="T2" type="text" id="T2" /><span id="L3"><br />Item3 Initial CSF <br /></span><input name="T3" type="text" id="T3" /><span id="L4"><br />Item4 Location <br /></span><input name="T4" type="text" id="T4" /><span id="L5"><br />Item5 Consultant <br /></span><input name="T5" type="text" id="T5" /></form>

once the user fills the form and click insert, i want to save entered text into a other tabel in the database using this code. it does not work. can u tell me where my mistake is?

Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click


    Dim mydb As New OleDbConnection
    mydb =
    New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source= |datadirectory|openclinica.mdb;Persist Security Info=True")
    mydb.Open()
    Dim Y As Integer = Session("Itemcount")
    For M = 1 To Y

        Session("FUt") = "L" + M.ToString
        Session("FUDt") = "T" + M.ToString

        Dim sqlstring = "INSERT INTO [Followup] ([MRN], [FU], [FUData]) VALUES (@MRNtxt, @" + Session("FUt") + ", @" + Session("FUDt") + ");"
        Dim mydbcommand As New OleDbCommand(sqlstring, mydb)
        mydbcommand.Parameters.Add("@MRNtxt", OleDbType.VarChar).Value = MRNtxt.Text
        mydbcommand.Parameters.Add("@" + Session("FUt"), OleDbType.VarChar).Value = Session("FUt").Text
        mydbcommand.Parameters.Add("@" + Session("FUDt"), OleDbType.VarChar).Value = Session("FUDt").Text
        mydbcommand.ExecuteNonQuery()

    Next

    mydb.Close()
End Sub

the error message looks like this when i click "insert"

enter image description here

I tried a lot and found this solution

Imports System.Data.OleDb

Partial Class _Default
Inherits System.Web.UI.Page

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

End Sub

Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click


    Dim mydb As New OleDbConnection
    mydb =
    New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source= |datadirectory|openclinica.mdb;Persist Security Info=True")
    mydb.Open()
    Dim part2 As Integer = Session("Itemcount")



    For Each C As Control In PlaceHolder1.Controls

        If TypeOf (C) Is TextBox Then

            Dim sqlstring = "insert into [followup] ([mrn], [fu], [fudata]) values (@mrntxt, @mylabel" + ", @mydata);"
            Dim mydbcommand As New OleDbCommand(sqlstring, mydb)
            mydbcommand.Parameters.Add("@mrntxt", OleDbType.VarChar).Value = MRNtxt.Text
            mydbcommand.Parameters.Add("@mylabel", OleDbType.VarChar).Value = C.ID
            mydbcommand.Parameters.Add("@mydata", OleDbType.VarChar).Value = CType(C, TextBox).Text
            mydbcommand.ExecuteNonQuery()
        End If
    Next

    mydb.Close()
End Sub




Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    InitializeCRF()
End Sub

Private Sub InitializeCRF()
    Dim CRFgrid As New GridView
    CRFgrid.DataSource = CRFds
    CRFgrid.DataBind()

    Dim ItemCount As Integer = CRFgrid.Rows.Count
    'Response.Write(ItemCount.ToString)
    Session("Itemcount") = CRFgrid.Rows.Count

    For I = 0 To (ItemCount - 1)
        Dim itemname As String = CRFgrid.Rows(0 + I).Cells(1).Text.ToString
        Session("Item") = "Item" + (I + 1).ToString
        Dim ItemNamelabel As New Label
        Dim ItemNameBox As New TextBox

        ItemNameBox.ID = itemname

        ItemNamelabel.Text = "<br/>" & itemname

        PlaceHolder1.Controls.Add(ItemNamelabel)
        PlaceHolder1.Controls.Add(ItemNameBox)


        ' Response.Write(itemname)
        ' Response.Write(", ")
    Next

End Sub
End Class

Is using thread local storage safe for this operation?

3 votes

I have a ASP.NET web application that allows end users to upload a file. Once the file is on the server, I spawn a thread to process the file. The thread is passed data regarding the specific operation (UserId, file path, various options, etc.). Most of the data is passed around via objects and method parameters but UserId needs to be available more globally so I put it in thread-local storage.

The thread is lengthy but it just processes the file and aborts. Is my use of the named data slot safe in this circumstance? If UserA uploads a file then UserB uploads a file while the first file is still processing, is it possible that the thread for UserA will also be delegated to handle UserB, thus producing a conflict for the named slot? (i.e. The slot gets overwritten with UserB's id and the rest of the operation of UserA's file is linked to the wrong User, UserB).

Public Class FileUploadProcess
    Public UserId as String

    Public Sub ExecuteAsync()
        Dim t As New Thread(New ThreadStart(AddressOf ProcessFile))
        t.Start()
    End Sub

    Protected Sub ProcessFile()
        Dim slot As LocalDataStoreSlot = Thread.GetNamedDataSlot("UserId")
        Thread.SetData(slot, UserId)

        'lengthy operation to process file

        Thread.FreeNamedDataSlot("UserId")
        Thread.CurrentThread.Abort()
    End Sub
End Class

Note that I am not asking if the LocalNamedDataStore slots are thread-safe. By definition, I know that they are.

In this case your use of thread local storage is safe. No two threads will ever share the same local storage (hence it's thread local). So there is no chance that two concurrent requests will stomp on the others data.

Couple of other comments though

  • Do avoid the use of Thread.Abort. It's a very dangerous operation and truthfully not needed here. The thread will end the statement afterwards.
  • A better approach would be to create a class which contains the background operation that has the UserId as a local field. Each request gets a new class instance. This is a much easier way to pass the data around to the background tasks