Windows Store App StreamSoket DataReader.LoadAsync() ObjectDisposedException - c#

I have problems with Windows 8 UI application. I'm using client-server communication and client needs to check new messages all time. So I use such code, where _socket is a StreamSoket:
private async static void MessageReceiver()
{
var dataReader = new DataReader(_socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
var stringHeader = await dataReader.LoadAsync(4);
if (stringHeader != 0)
{
var bytes = new byte[4];
dataReader.ReadBytes(bytes);
var length = BitConverter.ToInt32(bytes, 0);
var count = await dataReader.LoadAsync((uint) length);
var result = dataReader.ReadString(count);
ParseRequest(result);
}
dataReader.DetachStream();
MessageReceiver();
}
But in the second LoadAsync, when I try to read the string, I have ObjectDisposedException. Can you help me with it? I have no idea, why such exception is thrown.
I've also tried to use DataReader.InputStream.ReadAsync(), but I also had such problem.

I know this is an old post but since I was having the same problem and figured it out I thought I would post the solution for anyone else that stumbles across this. Although I won't claim to know exactly what the cause of this problem is, since I'm primarily a C++ guy, the solution was fairly simple.
The way I fixed it was by declaring the DataReader as a class member, thereby extending it's scope
_socket= new StreamSocket();
_socket.Control.KeepAlive = true;
_socket.Control.NoDelay = true;
_socketReader = new DataReader(_socket.InputStream);
_socketReader.InputStreamOptions = InputStreamOptions.Partial;
My possibly incorrect understanding of the await keyword is that the call is basically put on a new thread and that the rest of the function will continue off on the previous thread. Since the DataReader was declared locally, it will go out of scope once the function completes, leaving the await thread to work off of a disposed object.
If anybody wants to clarify this it would be appreciated.

Based of Alex Sorokoletov's last comment, my guess would be that the one of your important objects (probably the stream) would be disposed in the call to datareader.DetachStream();

Related

Aysnc method still blocking the ui interface

I have this method which is using ODBC and executes the reader async but the method is still blocking my UI for some reason it's loading 4000 records but I am wondering if someone can look at my code see where I am going wrong.
async Task<BindingList<PurchaseLinkHeaderC>> GetPurchaseOrders( IProgress<int> progress)
{
BindingList<PurchaseLinkHeaderC> _purhcaseOrderList = new BindingList<PurchaseLinkHeaderC>();
try
{
string sageDsn = ConfigurationManager.AppSettings["SageDSN"];
string sageUsername = ConfigurationManager.AppSettings["SageUsername"];
string sagePassword = ConfigurationManager.AppSettings["SagePassword"];
//using (var connection = new OdbcConnection("DSN=SageLine50v24;Uid=Manager;Pwd=;"))
using (var connection =
new OdbcConnection(String.Format("DSN={0};Uid={1};Pwd={2};", sageDsn, sageUsername, sagePassword)))
{
connection.Open();
string fromD = dtpFrom.Value.ToString("yyyy-MM-dd");
string toD = dtpTo.Value.ToString("yyyy-MM-dd");
string SQL =
"SELECT 'ORDER_NUMBER', 'ORDER_OR_QUOTE', 'ORDER_DATE', 'DELIVERY_DATE', 'ORDER_STATUS_CODE', 'ORDER_STATUS', 'DELIVERY_STATUS_CODE', 'DELIVERY_STATUS', 'ACCOUNT_REF', 'NAME', 'ADDRESS_1', 'ADDRESS_2', 'ADDRESS_3', 'ADDRESS_4', 'ADDRESS_5', 'C_ADDRESS_1', 'C_ADDRESS_2', 'C_ADDRESS_3', 'C_ADDRESS_4', 'C_ADDRESS_5', 'DEL_NAME', 'DEL_ADDRESS_1', 'DEL_ADDRESS_2', 'DEL_ADDRESS_3', 'DEL_ADDRESS_4', 'DEL_ADDRESS_5', 'VAT_REG_NUMBER', 'REFERENCE', 'CONTACT_NAME', 'TAKEN_BY', 'SUPP_ORDER_NUMBER', 'SUPP_TEL_NUMBER', 'NOTES_1', 'NOTES_2', 'NOTES_3', 'SUPP_DISC_RATE', 'FOREIGN_ITEMS_NET', 'FOREIGN_ITEMS_TAX', 'FOREIGN_ITEMS_GROSS', 'ITEMS_NET', 'ITEMS_TAX', 'ITEMS_GROSS', 'TAX_RATE_1', 'TAX_RATE_2', 'TAX_RATE_3', 'TAX_RATE_4', 'TAX_RATE_5', 'NET_AMOUNT_1', 'NET_AMOUNT_2', 'NET_AMOUNT_3', 'NET_AMOUNT_4', 'NET_AMOUNT_5', 'TAX_AMOUNT_1', 'TAX_AMOUNT_2', 'TAX_AMOUNT_3', 'TAX_AMOUNT_4', 'TAX_AMOUNT_5', 'COURIER_NUMBER', 'COURIER_NAME', 'CONSIGNMENT', 'CARR_NOM_CODE', 'CARR_TAX_CODE', 'CARR_DEPT_NUMBER', 'CARR_DEPT_NAME', 'FOREIGN_CARR_NET', 'FOREIGN_CARR_TAX', 'FOREIGN_CARR_GROSS', 'CARR_NET', 'CARR_TAX', 'CARR_GROSS', 'FOREIGN_INVOICE_NET', 'FOREIGN_INVOICE_TAX', 'FOREIGN_INVOICE_GROSS', 'INVOICE_NET', 'INVOICE_TAX', 'INVOICE_GROSS', 'CURRENCY', 'CURRENCY_TYPE', 'EURO_GROSS', 'EURO_RATE', 'FOREIGN_RATE', 'SETTLEMENT_DUE_DAYS', 'SETTLEMENT_DISC_RATE', 'FOREIGN_SETTLEMENT_DISC_AMOUNT', 'FOREIGN_SETTLEMENT_TOTAL', 'SETTLEMENT_DISC_AMOUNT', 'SETTLEMENT_TOTAL', 'PAYMENT_REF', 'PRINTED', 'PRINTED_CODE', 'POSTED', 'POSTED_CODE', 'QUOTE_STATUS_ID', 'RECURRING_REF', 'DUNS_NUMBER', 'PAYMENT_TYPE', 'BANK_REF', 'GDN_NUMBER', 'PROJECT_ID', 'ANALYSIS_1', 'ANALYSIS_2', 'ANALYSIS_3', 'INVOICE_PAYMENT_ID', 'RESUBMIT_INVOICE_PAYMENT_REQUIRED', 'RECORD_CREATE_DATE', 'RECORD_MODIFY_DATE', 'RECORD_DELETED' FROM 'PURCHASE_ORDER' WHERE ORDER_DATE >='{0}' and ORDER_DATE <='{1}'";
int counter = 0;
using (var command = new OdbcCommand(string.Format(SQL, fromD, toD), connection))
{
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
var purhcaseOrders = new PurchaseLinkHeaderC();
if ((reader["ORDER_NUMBER"] != ""))
{
counter++;
string orderNumber = Convert.ToString(reader["ORDER_NUMBER"]);
purhcaseOrders.Order_Number = OrderNumber.ToString();
purhcaseOrders.PurchaseOrderNo = Convert.ToInt32(reader["ORDER_NUMBER"]);
purhcaseOrders.Name = reader["NAME"].ToString();
purhcaseOrders.Selected_PurchaseOrder = false;
_purhcaseOrderList.Add(purhcaseOrders);
}
}
}
}
}
}
catch (Exception ex)
{
var logger = NLog.LogManager.GetCurrentClassLogger();
logger.Info(ex, "Error at GetSalesOrders " + ex.ToString());
}
return _purhcaseOrderList;
}
I want to be able to show a progress bar of the list being loaded so I was attempting to call it as this way. But I am not sure how to attach the progress method either.
var progressIndicator = new Progress<int>(ReportProgress);
//call async method
BindingList<PurchaseLinkHeaderC> purchaseOrders = await GetPurchaseOrders(progressIndicator);
_masterPurchaseOrders = purchaseOrders;
I am hoping that someone can help here.
When you await, the default behaviour is to use the sync-context, if one, when coming back from the async operation. In the case of a UI application, the sync-context is: the UI.
So; right now, there are a lot of things that come back to the UI. This is useful when context matters, but in your case: it doesn't - since you are simply returning a list.
This means that you should be able to add .ConfigureAwait(false) to a lot of those await expressions - for example:
while (await reader.ReadAsync().ConfigureAwait(false))
This disconnects the sync-context behaviour, and may improve what you are seeing. You would ideally to add that to all of the await calls in the utility method (GetPurchaseOrders).
You may also wish to look for any missing async operations - for example, the connection.Open(); could be a await connection.OpenAsync().ConfigureAwait(false);
Note that the calling code should not use ConfigureAwait(false) - since the binding-list touches the UI, it needs the sync-context. So: don't add ConfigureAwait(false) to the await GetPurchaseOrders(...) call.
There is also one other possibility: you say that you are using ODBC and "sage". It is entirely possible that the ODBC/sage API doesn't support await, and it is being implemented as "sync over async". If this is the case, it gets tricky. You might need to use a thread instead of async/await in that case - perhaps via ThreadPool.QueueUserWorkItem. There are ways to invoke async code on worker threads, but if the "async" code is actually "sync code that pretends to be async", there's not really any point, and you might as well do it "the old way". This usually means:
start a worker (ThreadPool)
do some work on the worker (your existing code, but perhaps using the non-async implementation)
at the end of the worker, use Control.Invoke to push the work back to the UI thread for the final "update the UI" step

Xamarin cannot access disposed object error

I am using the below code to read JSON from an endpoint in my Xamarin crossplatform project and I am getting error
Cannot read disposed object exception or it fires ObjectDisposedException
IS it something wrong with code Can I write it in a better way ?
public async Task<APISchoolDetailModel> GetSchooDetailsAsync()
{
APISchoolDetailModel api_data = new APISchoolDetailModel();
try
{
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
var web_client = await client.GetAsync("http://appapitest.net/APIs/Student/Schooldetails");
var response_string= web_client.Content.ReadAsStringAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(api_data.GetType());
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(response_string));
api_data = serializer.ReadObject(ms) as APISchoolDetailModel;
}
catch (Exception ex) { }
return api_data;
}
The controller comes till the line var web_client = await client.GetAsync(" and then its not going further and after few seconds I am getting exception
Is any better way to write this code for reading and parsing JSON
#Gserg pointed out something important you should not do this:
var response_string= web_client.Content.ReadAsStringAsync().Result;
in stead of that use:
var response_string= await web_client.Content.ReadAsStringAsync();
within an async Task method:
is you use .Result this may be causing deadlocks within threads or the same stuff that you are experiencing because a thread may be trying to update or use a variable that is already collected from the GC.

How do I make my application responsive during Entity Framework operations?

I have a fairly simple WPF application that uses Entity Framework. The main page of the application has a list of records that I am getting from a database on startup.
Each record has a picture, so the operation can be a little slow when the wireless signal is poor. I'd like this (and many of my SQL operations) to perform in the background if possible. I have async/await setup and at first it seemed to be working exactly as I wanted but now I'm seeing that my application is becoming unresponsive when accessing the DB.
Eventually I'm thinking I'm going to load up the text in one query and the images in another background operation and load them as they come in. This way I get the important stuff right away and the pictures can come in in the background, but the way things are going it's still looking like it will lock up if I do this.
On top of that, I'm trying to implement something to handle connectivity issues (in case the wifi cuts out momentarily) so that the application notifies the user of a connection issue, automatically retries a few times, etc. I put a try catch for SQL exception which seems to be working for me, but the whole application locks up for about a minute while it is trying to connect to the DB.
I tried testing my async/await using await Task.Delay() and everything is very responsive as expected while awaiting the delay, but everything locks up when awaiting the .ToListAsync(). Is this normal and expected? My understanding of async/await is pretty limited.
My code is kind of messy (I'm new) but it does what I need it to do for the most part. I understand there's probably plenty of improvements I can make and better ways to do things, but one step at a time here. My main goal right now is to keep the application from crashing during database accessing exceptions and to keep the user notified of what the application is doing (searching, trying to access db, unable to reach DB and retrying, etc) as opposed to being frozen, which is what they're going to think when they see it being unresponsive for over a minute.
Some of my code:
In my main view model
DataHelper data = new DataHelper();
private async void GetQualityRegisterQueueAsync()
{
try
{
var task = data.GetQualityRegisterAsync();
IsSearching = true;
await task;
IsSearching = false;
QualityRegisterItems = new ObservableCollection<QualityRegisterQueue>(task.Result);
OrderQualityRegisterItems();
}
catch (M1Exception ex)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine("QualityRegisterLogViewModel.GetQualityRegisterQueue() Operation Failed");
}
}
My Data Helper Class
public class DataHelper
{
private bool debugging = false;
private const int MAX_RETRY = 2;
private const double LONG_WAIT_SECONDS = 5;
private const double SHORT_WAIT_SECONDS = 0.5;
private static readonly TimeSpan longWait = TimeSpan.FromSeconds(LONG_WAIT_SECONDS);
private static readonly TimeSpan shortWait = TimeSpan.FromSeconds(SHORT_WAIT_SECONDS);
private enum RetryableSqlErrors
{
ServerNotFound = -1,
Timeout = -2,
NoLock = 1204,
Deadlock = 1205,
}
public async Task<List<QualityRegisterQueue>> GetQualityRegisterAsync()
{
if(debugging) await Task.Delay(5000);
var retryCount = 0;
using (M1Context m1 = new M1Context())
{
for (; ; )
{
try
{
return await (from a in m1.QualityRegisters
where (a.qanClosed == 0)
//orderby a.qanAssignedDate descending, a.qanOpenedDate
orderby a.qanAssignedDate.HasValue descending, a.qanAssignedDate, a.qanOpenedDate
select new QualityRegisterQueue
{
QualityRegisterID = a.qanQualityRegisterID,
JobID = a.qanJobID.Trim(),
JobAssemblyID = a.qanJobAssemblyID,
JobOperationID = a.qanJobOperationID,
PartID = a.qanPartID.Trim(),
PartRevisionID = a.qanPartRevisionID.Trim(),
PartShortDescription = a.qanPartShortDescription.Trim(),
OpenedByEmployeeID = a.qanOpenedByEmployeeID.Trim(),
OpenedByEmployeeName = a.OpenedEmployee.lmeEmployeeName.Trim(),
OpenedDate = a.qanOpenedDate,
PartImage = a.JobAssembly.ujmaPartImage,
AssignedDate = a.qanAssignedDate,
AssignedToEmployeeID = a.qanAssignedToEmployeeID.Trim(),
AssignedToEmployeeName = a.AssignedEmployee.lmeEmployeeName.Trim()
}).ToListAsync();
}
catch (SqlException ex)
{
Debug.WriteLine("SQL Exception number = " + ex.Number);
if (!Enum.IsDefined(typeof(RetryableSqlErrors), ex.Number))
throw new M1Exception(ex.Message, ex);
retryCount++;
if (retryCount > MAX_RETRY) throw new M1Exception(ex.Message, ex); ;
Debug.WriteLine("Retrying. Count = " + retryCount);
Thread.Sleep(ex.Number == (int)RetryableSqlErrors.Timeout ?
longWait : shortWait);
}
}
}
}
}
Edit: Mostly looking for general guidance here, though a specific example of what to do would be great. For these types of operations where I am downloading data, is it just a given that if I need the application to be responsive I need to be making multiple threads? Is that a common solution to this type of problem? Is this not something I should be expecting async/await to solve?
If you call this method from your UI thread, you will overload the capture of UI thread context and back on itself. Also, your service will not be necessarily "Performant" because it must wait until the UI thread is free before it can continue.
The solution is simple: just call the method passing the ConfigureAwait "false" parameter when you made the call.
.ToListAsync().ConfigureAwaiter(false);
I hope it helps

Windows store app, WCF Data Service InvalidOperationException when calling DataServiceQuery.EndExecute()?

I lookup relative data find that Windows store app only support async WCF calling to ensure the responsive UI. Here is a relative question.
I achieve my data service and do like that. Here is the code:
MyDataServiceContext ctx = new MyDataServiceContext(uri);
DataServiceQuery<COURSE_OK> query =
(DataServiceQuery<COURSE_OK>)(from crs in ctx.COURSE_OK
select crs);
TaskFactory<IEnumerable<COURSE_OK>> tf = new TaskFactory<IEnumerable<COURSE_OK>>();
var result = await tf.FromAsync(query.BeginExecute(null, null),
ira => query.EndExecute(ira)); // InvalidOperationException
foreach (var a in result)
{
System.Diagnostics.Debug.WriteLine("{0}", a.TITLE);
}
I succeeded only once, after that it always crash in query.EndExecute(ira) method and said InvalidOperationException was unhandled by user code.
In addition, it works well in Console Application. I guess that the main problem is Windows store app, but how to solve this?
Your function looks quite good. This is what works for me:
var queryTask = Task.Factory.FromAsync<IEnumerable<TResult>>(query.BeginExecute(null, null), (asResult) =>
{
var result = query.EndExecute(asResult).ToList();
return result;
});
Maybe you should not initialize your context on every call. Just initialize it once and reuse it every time you need it.

Instantiate a class in a separate thread without a compile time warning

Is it possible to instantiate a class in a separate thread without a compile time warning?
For example the below code gives the compile time error "Use of unassigned local variable BECheck". I would rather keep AvailabilityCheckBase abstract and not assign it some dummy variable. Creating both BTCheck and BECheck is slow which is why I need it threaded.
public static AvailabilityCheckBase ByDSL(string dsl)
{
AvailabilityCheckBase BECheck;
AvailabilityCheckBase BTCheck;
Thread BEThread = new Thread(new ThreadStart(() => BECheck = new BEAvailabilityCheck(dsl)));
Thread BTThread = new Thread(new ThreadStart(() => BTCheck = new BTAvailabilityCheck(dsl)));
BEThread.Join();
BTThread.Join();
return BECheck.Merge(BTCheck);
}
The language has no knowledge of the Thread constructor or the Join method: it can't tell that you will definitely assign values to both variables before Join returns. If you want to keep the current approach, you'll need to assign values to the variables first. I agree this is slightly ugly, but it's the only way of keeping the compiler happy here.
(It's not clear why you're creating two new threads here, given that your original thread is then blocking on both of them, by the way.)
A better approach if you're using .NET 4 would be to use Task<T>, which effectively gives you the "promise" of a value:
Task<AvailabilityCheckBase> beCheck =
Task.Factory.StartNew(() => new BEAvailabilityCheck(dsl));
Task<AvailabilityCheckBase> btCheck =
Task.Factory.StartNew(() => new BTAvailabilityCheck(dsl));
return beCheck.Result.Merge(btCheck.Result);
It's worth becoming familiar with Task<T> and the TPL in general, as the new async features in C# 5 are heavily dependent on them.
Doesn't this fix your compile error? :
change
AvailabilityCheckBase BECheck;
AvailabilityCheckBase BTCheck;
to
AvailabilityCheckBase BECheck = null;
AvailabilityCheckBase BTCheck = null;
In order to call BECheck.Merge in your last line, BECheck should be initialized, and the compiler doesn't know it will be created before Thread.Join.
Try writing
AvailabilityCheckBase BECheck = null;
AvailabilityCheckBase BTCheck = null;
in the first lines.
If you assign the values to null you should see the message disappear, this would be good practice. There also doesn't appear to be any checking to make sure that the initialisations worked, you should probably include a check for BECheck and BTCheck still being null at the end of the function before you try to return to avoid an exception being thrown.
Use Task's:
Task<AvailabilityCheckBase> BETask = new Task<AvailabilityCheckBase>(() => BECheck = new BEAvailabilityCheck(dsl));
Task<AvailabilityCheckBase> BTTask = new Task<AvailabilityCheckBase>(() => BECheck = new BTAvailabilityCheck(dsl));
BETask.WaitAll(BETask,BTTask);
AvailabilityCheckBase BECheck = BETask.Result;
AvailabilityCheckBase BTCheck = BTTask.Result;

Categories

Resources