I have three different databases that I need to check that I am connected to. This is what I originally have, which works perfectly fine.
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
return new ServiceAvailabilityDTO
{
IsDb1Online = await IsDb1Available(),
IsDb2Online = IsDb2Available(),
IsDb3Online = await IsDb3Available()
};
}
private async Task<bool> IsDb1Available()
{
var count = await _db1Service.GetDbCount();
if (count > 0)
return true;
return false;
}
private bool IsDb2Available()
{
if (_db2Service.GetDbCount() > 0)
return true;
return false;
}
private async Task<bool> IsDb3Available()
{
var pong = await _db3Provider.PingDb();
if(pong.Success == true && pong.Version != null)
return true;
return false;
}
Now however, I need to log exception messages in my DTO for each DB check.
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
return new ServiceAvailabilityDTO
{
IsDb1Online = await IsDb1Available(),
IsDb2Online = IsDb2Available(),
IsDb3Online = await IsDb3Available(this) // This is an example. I want to pass the reference of **ServiceAvailabilityDTO** to **IsDb3Available**
};
}
private async Task<bool> IsDb3Available(ServiceAvailabilityDTO availability)
{
try
{
var pong = await _db3Provider.PingDb();
if(pong.Success == true && pong.Version != null)
return true;
return false;
}
catch (Exception e)
{
var exceptionMessage = e.Message;
if (e.InnerException != null)
{
// This is what I hope to put into the object reference
exceptionMessage = String.Join("\n", exceptionMessage, e.InnerException.Message);
availability.db3Exception = exceptionMessage ;
}
return false;
}
}
My question is;
Can I keep my return method the same as in the first example, and pass the object reference to each method to store the exception and still return my bool value.
Or does the object not get created until all of the method calls have happened, and then create the object with the returned values?
I know I could just create the object normally and pass it in each
method call, but it is specifically this way of doing it that has
inspired me to ask this question, purely to be informed and learn
from.
Thanks.
No, you cannot do it like this because in the context of what you're doing this does not refer to the object you're populating, it refers to the object containing the method you're calling.
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
return new ServiceAvailabilityDTO
{
IsDb1Online = await IsDb1Available(),
IsDb2Online = IsDb2Available(),
IsDb3Online = await IsDb3Available(this) // here 'this' does NOT ref to ServiceAvailabilityDTO
};
}
There is no keyword which does refer to ServiceAvailabilityDTO either, so you're left with creating the object, and passing it to each method. At this point, I dont think there is much point you returning the boolean either - you may as well set the boolean property in line
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
var sa = new ServiceAvailabilityDTO();
await CheckDb1Available(sa);
CheckDb2Available(sa);
await CheckDb3Available(sa);
return sa;
}
(Note I've renamed the methods from Is* to Check* as the former implies a return boolean, the latter implies something going on inline.)
Related
I found this class online:
public class AsyncSearcher
{
LdapConnection _connect;
public AsyncSearcher(LdapConnection connection)
{
this._connect = connection;
this._connect.AutoBind = true; //will bind on first search
}
public void BeginPagedSearch(
string baseDN,
string filter,
string[] attribs,
int pageSize,
Action<SearchResponse> page,
Action<Exception> completed
)
{
if (page == null)
throw new ArgumentNullException("page");
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(null);
Action<Exception> done = e =>
{
if (completed != null) asyncOp.Post(delegate
{
completed(e);
}, null);
};
SearchRequest request = new SearchRequest(
baseDN,
filter,
System.DirectoryServices.Protocols.SearchScope.Subtree,
attribs
);
PageResultRequestControl prc = new PageResultRequestControl(pageSize);
//add the paging control
request.Controls.Add(prc);
AsyncCallback rc = null;
rc = readResult =>
{
try
{
var response = (SearchResponse)_connect.EndSendRequest(readResult);
//let current thread handle results
asyncOp.Post(delegate
{
page(response);
}, null);
var cookie = response.Controls
.Where(c => c is PageResultResponseControl)
.Select(s => ((PageResultResponseControl)s).Cookie)
.Single();
if (cookie != null && cookie.Length != 0)
{
prc.Cookie = cookie;
_connect.BeginSendRequest(
request,
PartialResultProcessing.NoPartialResultSupport,
rc,
null
);
}
else done(null); //signal complete
}
catch (Exception ex) { done(ex); }
};
//kick off async
try
{
_connect.BeginSendRequest(
request,
PartialResultProcessing.NoPartialResultSupport,
rc,
null
);
}
catch (Exception ex) { done(ex); }
}
}
I am basically trying to convert the below code which writes to the console to return data from Task.Factory.FromAsync, so that I can use the data elsewhere.
using (LdapConnection connection = CreateConnection(servername))
{
AsyncSearcher searcher = new AsyncSearcher(connection);
searcher.BeginPagedSearch(
baseDN,
"(sn=Dunn)",
null,
100,
f => //runs per page
{
foreach (var item in f.Entries)
{
var entry = item as SearchResultEntry;
if (entry != null)
{
Console.WriteLine(entry.DistinguishedName);
}
}
},
c => //runs on error or when done
{
if (c != null) Console.WriteLine(c.ToString());
Console.WriteLine("Done");
_resetEvent.Set();
}
);
_resetEvent.WaitOne();
}
I tried this but get the following syntax errors:
LdapConnection connection1 = CreateConnection(servername);
AsyncSearcher1 searcher = new AsyncSearcher1(connection1);
async Task<SearchResultEntryCollection> RootDSE(LdapConnection connection)
{
return await Task.Factory.FromAsync(,
() =>
{
return searcher.BeginPagedSearch(baseDN, "(cn=a*)", null, 100, f => { return f.Entries; }, c => { _resetEvent.Set(); });
}
);
}
_resetEvent.WaitOne();
The APM ("Asynchronous Programming Model") style of asynchronous code uses Begin and End method pairs along with IAsyncResult, following a specific pattern.
The Task.Factory.FromAsync method is designed to wrap APM method pairs into a modern TAP ("Task-based Asynchronous Programming") style of asynchronous code.
However, FromAsync requires the methods to follow the APM pattern exactly, and BeginPagedSearch does not follow the APM pattern. So you will need to use TaskCompletionSource<T> directly. TaskCompletionSource<T> can be used to convert any existing asynchronous pattern to TAP as long as it has a single result.
The method you're trying to wrap has multiple callbacks, so it can't be mapped to TAP at all. If you want to collect all result sets and return a list of them, then you can use TaskCompletionSource<T> for that. Otherwise, you'll want to use something like IAsyncEnumerable<T>, which would require writing your own implementation of BeginPagedSearch.
How can I make repetitive calls to a URL by time intervals till I get successful result or timeout?
I upload a file to an API and it sends me a URL to let me check if my file is processed successfully. I want to make it so this url is checked in the server until the pending status is changed. There are successful, failed and pending statuses. I want to keep the user wait until the result is either fail or success.
[HttpGet]
public async Task<ActionResult> Get()
{
...
response = await client.GetAsync(other_api_url);
if(response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
dynamic output = JsonConvert.DeserializeObject<dynamic>(result);
statusUrl = output.url_to_check_status;
//make a call to statusUrl check if content is ready
//get result and parse it
...
status = output.status;
if(status == "SUCCESS")
{
//good path
return Ok();
}
else
{
//make another call after n seconds to check again
}
}
return NotFound();
}
You can use a loop with Task.Delay, like this:
bool done = false;
while (!done)
{
await Task.Delay(1000);
done = await GetStatusFromServerAsync();
}
Although you might want a timeout:
async Task<bool> CheckForCompletion(int timeoutms)
{
var timer = StopWatch.StartNew();
while (timer.ElapsedMilliseconds < timeoutms)
{
var ok = await GetStatusFromServerAsync();
if (ok) return true;
await Task.Yield(1000);
}
return false;
}
Not that I'd agree to doing this (you should never block your request this way), but I think this should solve your problem:
[HttpGet]
public async Task<ActionResult> Get()
{
response = await client.GetAsync(other_api_url);
if(response.IsSuccessStatusCode)
{
// DO NOT USE `.Result` within async method.
string result = await response.Content.ReadAsStringAsync();
dynamic output = JsonConvert.DeserializeObject<dynamic>(result);
statusUrl = output.url_to_check_status;
bool? result = null;
while(result == null) result = await CheckIfSuccessfulAsync(statusUrl);
if (result) return Ok();
return NotFound();
}
}
// Does not *need* to be a separate method, it's just for better readability...
private async Task<bool?> CheckIfSuccessfulAsync(string statusUrl)
{
//make a call to statusUrl check if content is ready
//get result and parse it
...
status = output.status;
if (status == "SUCCESS") return true;
else if (status == "PENDING") return false;
return null;
}
I am passing some value from one page to another page via query string, it passes the values correctly and then passes to the stored procedure succesfully but typing the Request.QueryString["something"] again and again is very irritating, so I created a method for it, but the method does not return/passes any value and the nullreference exception is thrown.
protected void Page_Load(object sender, EventArgs e)
{
try
{
using (Property_dbDataContext context = new Property_dbDataContext())
{
_errMsg.Enabled = false;
_errMsg.Visible = false;
var find_prop = context.find_property(val("city"), val("type"), val("subtype"), val("bedrooms"), val("size_unit"), Convert.ToInt32(val("area_from")), Convert.ToInt32(val("areato")), Convert.ToInt32(val("pricefrom")), Convert.ToInt32(val("priceto"))).ToList();
//code above does not return any value
//var find_prop = context.find_property(Request.QueryString["city"], Request.QueryString["type"], Request.QueryString["subtype"], Request.QueryString["bedrooms"], Request.QueryString["size_unit"], Convert.ToInt32(Request.QueryString["area_from"]), Convert.ToInt32(Request.QueryString["areato"]), Convert.ToInt32(Request.QueryString["pricefrom"]), Convert.ToInt32(Request.QueryString["priceto"])).ToList();
//code above return value from the database but its a long procedure
rptr_properties.DataSource = find_prop;
rptr_properties.DataBind();
}
}
catch(Exception ex)
{
_errMsg.Enabled = true;
_errMsg.Visible = true;
_errMsg.Text = "Sorry! Property not found." + ex;
}
}
public string val(string a)
{
return Request.QueryString["" + a + ""].ToString();
}
You need to make sure the item exists before trying to access it:
public string val(string a)
{
if(Request.QueryString[a] != null)
return Request.QueryString[a].ToString();
return string.Empty;
}
In reference to your comment; this in particular:
Convert.ToInt32(val("area_from"))
Is going to cause a problem because the default value is an empty string.
Something like this should work for now though:
public string ValToString(string a)
{
if(Request.QueryString[a] != null)
return Request.QueryString[a].ToString();
return string.Empty;
}
public int ValToInt32(string a)
{
if(Request.QueryString[a] != null)
return Convert.ToInt32(Request.QueryString[a]);
return 0;
}
You would then modify your find code:
var find_prop = context.find_property(ValToString("city"), ValToString("type"), ValToString("subtype"), ValToString("bedrooms"), ValToString("size_unit"), Convert.ToInt32(val("area_from")), Convert.ToInt32(val("areato")), ValToInt32("pricefrom"), ValToInt32("priceto")).ToList();
This will work
public string val(string a)
{
return Request.QueryString[a];
}
Better method for converting a querystring value to an int(32):
public int GetIntFromQueryString(string key)
{
int result = int.MinValue;
if(Request.QueryString[key] != null)
{
int.TryParse(Request.QueryString[key].ToString(), out result);
}
return result;
}
If TryParse fails to convert the value the method will return 'int.MinValue', you can then check the returned value does not equal 'int.MinValue' and go from there.
I am trying to save some data to a SQLite3 database. If I do not use async, I can save the data without any problems. As soon as I try to use the following code however, I receive the following error:
{Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}
From my UI, I invoke the following SyncDomainTablesAsync method:
private readonly IDataCoordinator _coordinator;
public Configuration(IDataCoordinator coordinator)
{
_coordinator = coordinator;
}
public async Task<int> SyncDomainTablesAsync(IProgress<string> progress, CancellationToken ct, DateTime? lastDateSynced=null, string tableName = null)
{
//Determine the different type of sync calls
// 1) Force Resync (Drop/Create Tables and Insert)
// 2) Auto Update
var domainTable = await GetDomainTablesAsync(progress,ct,lastDateSynced, tableName);
var items = domainTable.Items;
int processCount = await Task.Run<int>( async () =>
{
int p = 0;
progress.Report(String.Format("Syncing Configurations..."));
foreach (var item in items)
{
progress.Report(String.Format("Syncing {0} Information",item.Key));
var task = await SyncTableAsync(item.Value); // INVOKED BELOW
if (task) progress.Report(String.Format("Sync'd {0} {1} records", item.Value.Count,item.Key));
if (ct.IsCancellationRequested) goto Cancelled;
p += item.Value.Count;
}
Cancelled:
if (ct.IsCancellationRequested)
{
//Update Last Sync'd Records
progress.Report(String.Format("Canceling Configuration Sync..."));
ct.ThrowIfCancellationRequested();
}
else
progress.Report(String.Format("Syncing Configurations Compleleted"));
return p;
},ct);
return processCount;
}
private async Task<bool> SyncTableAsync(IEnumerable<object> items, bool includeRelationships = false)
{
try
{
//TODO: Replace with SaveObjects method
var i = await Task.Run(() => _coordinator.SaveObjects(items, includeRelationships));
if (i == 0)
return false;
}
catch(Exception ex)
{
return false;
}
return true;
}
The UI invokes the SyncDomainTablesAsync method. I then create a new Task and loop through the items that were returned from the GetDomainTablesAsync method. During each iteration I await until the SyncTableAsync method completes. Within the SyncTableAsync I am calling a SaveObject method inside of a class that implements my IDataCoordinator interface.
public override int SaveObjects(IEnumerable<object> items, Type underlyingType, bool saveRelationships = true)
{
int result = 0;
if (items == null)
throw new ArgumentNullException("Can not save collection of objects. The collection is null.");
else if (items.Count() == 0)
return 0;
// Check if table exists.
foreach (var item in items)
this.CreateTable(item.GetType(), saveRelationships);
using (SQLiteConnection connection = new SQLiteConnection(this.StorageContainerPath))
{
connection.BeginTransaction();
foreach (var item in items)
{
result += ProcessSave(item, saveRelationships, connection);
}
try
{
connection.Commit();
}
catch (SQLiteException ex)
{
connection.Rollback();
throw ex;
}
}
return result;
}
public override int CreateTable(Type type, bool createRelationalTables = false)
{
if (this.TableExists(type) == 1)
return 1;
using (SQLiteConnection cn = new SQLiteConnection(this.StorageContainerPath))
{
try
{
// Check if the Table attribute is used to specify a table name not matching that of the Type.Name property.
// If so, we generate a Sql Statement and create the table based on the attribute name.
//if (Attribute.IsDefined(type, typeof(TableAttribute)))
//{
// TableAttribute attribute = type.GetAttribute<TableAttribute>();
// Strongly typed to SQLiteCoordinator just to get a SqlQuery instance. The CreateCommand method will create a table based on 'type'
var query = new SqlQuery<SQLiteCoordinator>().CreateCommand(DataProviderTypes.Sqlite3, type);
query = query.TrimEnd(';') + ";";
cn.Execute(query);
//}
// Otherwise create the table using the Type.
//else
//{
// cn.CreateTable(type);
//}
// If we are to create relationship tables, we cascade through all relationship properties
// and create tables for them as well.
if (createRelationalTables)
{
this.CreateCascadingTables(type, cn);
}
}
catch (Exception ex)
{
return 0;
}
}
return 1;
}
The flow of the code goes
UI->SyncDomainTablesAsync->SyncTableAsync->SaveObjects->SaveTable(type)
The issue that I have is within Save Table. If I just use SaveTable synchronously I have no issues. Using it in my async method above, causes a thread abort exception. The exception is thrown within the SQLite.cs file included with SQLite.net (within the . The weird thing is that the table is created in the database, even though the exception is thrown. The error is thrown some times when the Prepare() function is called and the rest of the time when the SQLite3.Step() function is called.
public int ExecuteNonQuery ()
{
if (_conn.Trace) {
Debug.WriteLine ("Executing: " + this);
}
var r = SQLite3.Result.OK;
var stmt = Prepare (); // THROWS THE ERRROR
r = SQLite3.Step(stmt); // THROWS THE ERRROR
Finalize(stmt);
if (r == SQLite3.Result.Done) {
int rowsAffected = SQLite3.Changes (_conn.Handle);
return rowsAffected;
} else if (r == SQLite3.Result.Error) {
string msg = SQLite3.GetErrmsg (_conn.Handle);
throw SQLiteException.New (r, msg);
} else {
throw SQLiteException.New (r, r.ToString ());
}
}
I assume that because my foreach statement awaits the return of SyncTableAsync that none of the threads are closed. I am also getting a system transaction critical exception that says "attempting to access a unloaded app domain".
Am I using await/async incorrectly with Sqlite3 or is this an issue with Sqlite3 that I am not aware of.
Attached is a photo of the Parallel's stack and the exception.
EDIT
When I try to run the code above as well in unit tests, the unit tests process never dies. I have to exit Visual Studio in order to get the process to die. I am assuming something in SQLite.dll is grabbing a hold of the process when the exception is thrown and not letting go, but I am not sure.
EDIT 2
I can modify the initial method SyncDomainTablesAsync to the following and the code runs without error. The issue is my use of async and await I believe.
public async Task<int> SyncDomainTablesAsync(IProgress<string> progress, CancellationToken ct, DateTime? lastDateSynced=null, string tableName = null)
{
var domainTable = await GetDomainTablesAsync(progress,ct,lastDateSynced, tableName);
var items = domainTable.Items;
foreach (var item in items)
{
_coordinator.SaveObjects(item.Value, typeof(object), true);
}
return 1;
}
For my app I make calls to a web service to get customer data. The problem I am encountering is when I make this particular call it gets the the asynchronous await call and loops back without finishing the call and then storing the results.
private void DatabaseTest()
{
cNum = Convert.ToString(db.selectCustomerNumber());
callC = "SELECT * FROM dashboardCustomer WHERE period = 'C' AND customerNumber = " + cNum;
callB = "SELECT * FROM dashboardCustomer WHERE period = 'B' AND customerNumber = " + cNum;
callF = "SELECT * FROM dashboardCustomer WHERE period = 'F' AND customerNumber = " + cNum;
if (db.selectDashboard(callC).Count == 0)
{
GetDataSummary(passC);
}
if (db.selectDashboard(callB).Count == 0)
{
GetDataSummary(passB);
}
if (db.selectDashboard(callF).Count == 0)
{
GetDataSummary(passF);
}
}
private async void GetDataSummary(string r)
{
long customerNum = db.selectCustomerNumber();
pin = db.selectPinByCustomerNumber(customerNum);
string cType = r;
try
{
Windows.Security.Credentials.PasswordVault vault = new Windows.Security.Credentials.PasswordVault();
IReadOnlyList<PasswordCredential> userCredential = vault.FindAllByResource(pin);
userCredential[0].RetrievePassword();
try
{
getCustomerBillSummaryResponse billSum = await
UBPclient.getCustomerBillSummaryAsync(userCredential[0].UserName, userCredential[0].Password, customerNum, cType);
invoiceSummaryBean[] summaryList = billSum.#return;
rh.DashboardHandler(summaryList, customerNum);
}
catch
{
}
}
catch
{
}
}
it runs to the following part
getCustomerBillSummaryResponse billSum = await
UBPclient.getCustomerBillSummaryAsync(userCredential[0].UserName, userCredential[0].Password, customerNum, cType);
and then loops back to the try and runs again until it has ran three times.
How do I make it return the data it is suppose to for each call and store it in my database?
Also I have tested the web service in SoapUI and the call is returning results, so the problem is not with the web service.
You need to do this:
private async Task GetDataSummary(string r)
You need to return Task instead of void because your caller needs to have something to wait for. When you return void, the caller must treat method as "fire-and-forget". When you return Task, the caller can create the necessary code to await for async method to finish.
And don't forget to add the await keyword when you call it: await GetDataSummaryAsync(...);
You should avoid async void. Change GetDataSummary to return Task and then await it from DatabaseTest:
private async Task DatabaseTestAsync()
{
...
if (db.selectDashboard(callC).Count == 0)
{
await GetDataSummaryAsync(passC);
}
if (db.selectDashboard(callB).Count == 0)
{
await GetDataSummaryAsync(passB);
}
if (db.selectDashboard(callF).Count == 0)
{
await GetDataSummaryAsync(passF);
}
}
private async Task GetDataSummaryAsync(string r)