process locking / multithreading / and polling

  • Thread starter Thread starter pbd22
  • Start date Start date
P

pbd22

Hi.

I need some help on progress updates for file uploads.

I have Page.aspx.cs and, in the codebehind, I have a loop:

List<ServerVariable> files = new List<ServerVariable>();

for (i = 0; i <= Request.Files.Count - 1; i++)
{

m_objFile = Request.Files;
m_strFileName = m_objFile.FileName;
m_strFileName = Path.GetFileName(m_strFileName);

files.Add(new Status(0, this.m_strFileName,
DateTime.Now));

}

//CODE TO COPY A FILE FOR UPLOAD TO THE
//WEB SERVER

//WHEN THE UPLOAD IS DONE, SET THE ITEM TO
//COMPLETED

int index = files.FindIndex(p => p.Completed == "0");
files[index] = new ServerVariable(1, this.m_strFileName,
DateTime.Now);

Now, I have a client method that uses JQuery/AJAX/JSON to poll a Web
Service (named GetStatus) at intervals with the intent of returning a
JSON string describing which files have not started, which files are
in progress, and which files are completed.

MY QUESTION IS how do I handle the logic so the loop that is setting
data is not deadlocked by the AJAX call that is getting data? Using
code examples online, I have the following class:

public class Status
{
private int _flag; // 0 before upload. 1 at completion.
private string _fileName;
private DateTime _lastUpdate;
private object _sync = new object(); // single lock for both
fields

public Status(int _flag, string _fileName, DateTime
_lastUpdate)
{
this.Flag = _flag;
this.FileName = _fileName;
this.LastUpdate = _lastUpdate;
}

public int Flag
{
get { lock (_sync) { return _flag; } }
set
{
lock (_sync)
{
_flag = value;
}

// Notify listeners
EventHandler handler = Changed;
if (handler != null)
{
handler(this, null);
}
}
}

public string FileName
{
get { lock (_sync) { return _fileName; } }
set { lock (_sync) { _fileName = value; } }
}

public DateTime LastUpdate
{
get { lock (_sync) { return _lastUpdate; } }
set { lock (_sync) { _lastUpdate = value; } }
}

public event EventHandler Changed;
}

Will the above prevent deadlocks as data setting/getting happens? I
would prefer to do it this way if I can.

The below code is where I need help. I am attempting to access
data updates to my Status properties when the AJAX call comes in and
return the data to the client.

This is new territory for me and the code below is based on online
reading. Can somebody comment on what is going on here and correct me
(code examples appreciated) if I am off the mark. Thanks in advance.

List<Status> IUploadService.GetStatus()
{

Status status = new Status();
ManualResetEvent changedEvent = new ManualResetEvent
(false);
Thread thread = new Thread(
delegate() {
status.Changed += delegate { changedEvent.Set();};
while (true) {
changedEvent.WaitOne(Timeout.Infinite);
int flag = status.Flag;
string file = status.FileName;
DateTime lastUpdate = status.LastUpdate;
changedEvent.Reset();
}
}
);

//return progress as a List

}
 
you have a couple problems:

1) each http request is a new class instance of the page, so the files
created in a postback, is not the sameone seen in a webmetod. in fact
each webmethod poll will see a different files. you must make files
available to all requests, storing in static collection with a key.

2) asp.net queues up requests that use session, so be sure the page
request, and the poll do not use session. probably have to move the
method to webservice.

3) the browser limits the concurrent callbacks, so you will have trouble
polling during a postback. your postback server code should use a worker
thread to the processing and return right away.


-- bruce (sqlwork.com)

Hi.

I need some help on progress updates for file uploads.

I have Page.aspx.cs and, in the codebehind, I have a loop:

List<ServerVariable> files = new List<ServerVariable>();

for (i = 0; i <= Request.Files.Count - 1; i++)
{

m_objFile = Request.Files;
m_strFileName = m_objFile.FileName;
m_strFileName = Path.GetFileName(m_strFileName);

files.Add(new Status(0, this.m_strFileName,
DateTime.Now));

}

//CODE TO COPY A FILE FOR UPLOAD TO THE
//WEB SERVER

//WHEN THE UPLOAD IS DONE, SET THE ITEM TO
//COMPLETED

int index = files.FindIndex(p => p.Completed == "0");
files[index] = new ServerVariable(1, this.m_strFileName,
DateTime.Now);

Now, I have a client method that uses JQuery/AJAX/JSON to poll a Web
Service (named GetStatus) at intervals with the intent of returning a
JSON string describing which files have not started, which files are
in progress, and which files are completed.

MY QUESTION IS how do I handle the logic so the loop that is setting
data is not deadlocked by the AJAX call that is getting data? Using
code examples online, I have the following class:

public class Status
{
private int _flag; // 0 before upload. 1 at completion.
private string _fileName;
private DateTime _lastUpdate;
private object _sync = new object(); // single lock for both
fields

public Status(int _flag, string _fileName, DateTime
_lastUpdate)
{
this.Flag = _flag;
this.FileName = _fileName;
this.LastUpdate = _lastUpdate;
}

public int Flag
{
get { lock (_sync) { return _flag; } }
set
{
lock (_sync)
{
_flag = value;
}

// Notify listeners
EventHandler handler = Changed;
if (handler != null)
{
handler(this, null);
}
}
}

public string FileName
{
get { lock (_sync) { return _fileName; } }
set { lock (_sync) { _fileName = value; } }
}

public DateTime LastUpdate
{
get { lock (_sync) { return _lastUpdate; } }
set { lock (_sync) { _lastUpdate = value; } }
}

public event EventHandler Changed;
}

Will the above prevent deadlocks as data setting/getting happens? I
would prefer to do it this way if I can.

The below code is where I need help. I am attempting to access
data updates to my Status properties when the AJAX call comes in and
return the data to the client.

This is new territory for me and the code below is based on online
reading. Can somebody comment on what is going on here and correct me
(code examples appreciated) if I am off the mark. Thanks in advance.

List<Status> IUploadService.GetStatus()
{

Status status = new Status();
ManualResetEvent changedEvent = new ManualResetEvent
(false);
Thread thread = new Thread(
delegate() {
status.Changed += delegate { changedEvent.Set();};
while (true) {
changedEvent.WaitOne(Timeout.Infinite);
int flag = status.Flag;
string file = status.FileName;
DateTime lastUpdate = status.LastUpdate;
changedEvent.Reset();
}
}
);

//return progress as a List

}
 
Thanks for your reply Bruce. Followup below:
1) each http request is a new class instance of the  page, so the files
created in a postback, is not the sameone seen in a webmetod. in fact
each webmethod poll will see a different files. you must make files
available to all requests, storing in static collection with a key.

Maybe you could help me understand this further. There is only one
postback
going on here - the moment when the user clicks "UPLOAD" on the page
and submits the form. At this point the upload string is sent to the
server and accessed as a File collections (Request.Files).

At the moment the user clicks "upload" he is also firing the jquery
method that is polling the Web Service I have created - GetStatus().

If something about this is incorrect, would you mind being more
specific about what needs to be done and where?
2) asp.net queues up requests that use session, so be sure the page
request, and the poll do not use session. probably have to move the
method to webservice.

I think I have been unclear. I am indeed using a Web Service and
my GetStatus() method is being exposed using UploadService.cs /
IUploadService.cs / Upload.cs via Upload.svc. In the JQuery / AJAX /
JSON
method that gets fired when the user submits the form, I am calling:

$.getJSON("http://localhost:2541/project09/upload.svc/getstatus", ...
etc

So, I am not using sessions.
3) the browser limits the concurrent callbacks, so you will have trouble
polling during a postback. your postback server code should use a worker
thread to the processing and return right away.

OK. So, it sounds like firing my AJAX method at the same time that the
upload form is doing a postback is a bad design. I can see that -
maybe I should have the client method wait at an interval? As for
having my codebehind of the submitted form use a worker thread - can
you expand or that? This is the code that is setting the file upload
status in my Status class (which, in turn, is called by my Web
Service). Will the use of a worker thread help to solve concurrency
problems?
 
Back
Top