I am overriding SaveChangesAsync to handle DbUpdateConcurrencyException. For example:
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
var saved = false;
var loopCount = 0;
var count = 0;
while (!saved && ++loopCount < 4)
{
try
{
count = await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
saved = true;
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
entry.OriginalValues.SetValues(entry.CurrentValues);
}
}
}
return count;
}
My question is: how do I force the base class (DbContext) to throw a DbUpdateConcurrencyException in a test?
Note: Please don't suggest wrapping or other abstractions as those are certainly overkill in this case.
Related
I want to make ActionResult with run a thread. When thread are running I will return View with loading but when thread finished the ActionResult return the another View
My code look like:
private static void ExecuteScrapper()
{
ScriptEngine pythonEngine = IronPython.Hosting.Python.CreateEngine();
ScriptSource pythonScript = pythonEngine.CreateScriptSourceFromFile(HostingEnvironment.MapPath("/PythonScript/main.py"));
var searchPath = pythonEngine.GetSearchPaths();
searchPath.Add(HostingEnvironment.MapPath("/PythonScript/"));
searchPath.Add(HostingEnvironment.MapPath("/PythonScript/drivers/"));
pythonEngine.SetSearchPaths(searchPath);
var result = pythonScript.Execute();
}
private ScrapperEnum.ScrapperOperations scraperParam;
private Thread t = new Thread(new ThreadStart(ExecuteScrapper));
public ActionResult RunScrapper(ScrapperEnum.ScrapperOperations operation)
{
scraperParam = operation;
t.Start();
bool run = false;
while(t.IsAlive)
{
if(!run)
{
run = true;
return View("ScrapperLoadingView");
}
}
return RedirectToAction("Scrapper");
}
I don't know exactly how to do that, because when in this code I return ScrapperLoginView it will break while so the function don't switch the View
You just need to add an else if I'm correct
while(t.IsAlive)
{
if(!run)
{
run = true;
return View("ScrapperLoadingView");
}
else
{
return RedirectToAction("Scrapper");
}
}
}
I am implementing CoinPayments IPN in my application and I have trouble with passing data to the method that take their Callback. I have tried like everything I could find: TempData, SessionVariables, tried to implement it somewhere in forms and maybe Request it but that didn`t work for me. So I also tried to implement it with Global static variables. And it worked! But then came another issue: if more than one user were to buy something from website at the same time or even in between any callbacks their data will get mixed. So here I am, trying again to make Session Variables work and have no clue why they are not working as I used them before. Probably what I can think of is that because its a callback from CoinPayments and I handle something wrongly.
Here is the code I have right now: Tho I tried different variations like implementing Session in Get Payment method. Now I ended up with it and it still comes out as null in POST METHOD.
Class for handling Session Variables:
public static class MyGlobalVariables
{
public static int TokenChoice
{
get
{
if (System.Web.HttpContext.Current.Session["TokenChoice"] == null)
{
return -1;
}
else
{
return (int)System.Web.HttpContext.Current.Session["TokenChoice"];
}
}
set
{
System.Web.HttpContext.Current.Session["TokenChoice"] = value;
}
}
public static int PaymentChoice
{
get
{
if (System.Web.HttpContext.Current.Session["PaymentChoice"] == null)
{
return -1;
}
else
{
return (int)System.Web.HttpContext.Current.Session["PaymentChoice"];
}
}
set
{
System.Web.HttpContext.Current.Session["PaymentChoice"] = value;
}
}
public static string CurrentUser
{
get
{
System.Web.HttpContext.Current.Session["CurrentUser"] = System.Web.HttpContext.Current.User.Identity.Name;
return (string)System.Web.HttpContext.Current.Session["CurrentUser"];
}
}
}
Class that returns view where you click on CoinPayments button:
public ActionResult Payment(int tokenChoice, int paymentChoice)
{
ViewBag.Payment = paymentChoice;
MyGlobalVariables.PaymentChoice = paymentChoice;
MyGlobalVariables.TokenChoice = tokenChoice;
return View();
}
Callback class that handles Callback from CoinPayments:
[HttpPost]
public ActionResult Payment()
{
NameValueCollection nvc = Request.Form;
var merchant_id = id;
var ipn_secret = secret;
var order_total = MyGlobalVariables.PaymentChoice;
if (String.IsNullOrEmpty(nvc["ipn_mode"]) || nvc["ipn_mode"] != "hmac")
{
Trace.WriteLine("IPN Mode is not HMAC");
return View();
}
if (String.IsNullOrEmpty(HTTP_HMAC))
{
Trace.WriteLine("No HMAC signature sent");
return View();
}
if (String.IsNullOrEmpty(nvc["merchant"]) || nvc["merchant"] != merchant_id.Trim())
{
Trace.WriteLine("No or incorrect Merchant ID passed");
return View();
}
//var hmac = hash_hmac("sha512", request, ipn_secret.Trim());
var txn_id = nvc["txn_id"];
var item_name = nvc["item_name"];
var item_number = nvc["item_number"];
var amount1 = nvc["amount1"];
var amount2 = float.Parse(nvc["amount2"], CultureInfo.InvariantCulture.NumberFormat);
var currency1 = nvc["currency1"];
var currency2 = nvc["currency2"];
var status = Convert.ToInt32(nvc["status"]);
var status_text = nvc["status_text"];
Trace.WriteLine(status);
if (currency1 != "USD") {
Trace.WriteLine("Original currency mismatch!");
return View();
}
if (Convert.ToInt32(amount1) < Convert.ToInt32(order_total))
{
Trace.WriteLine("Amount is less than order total!");
return View();
}
if (status >= 100 || status == 2) {
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
if (account != null && account.Paid == 0)
{
Trace.WriteLine("Payment Completed");
Trace.WriteLine("Tokens to add: " + MyGlobalVariables.TokenChoice);
account.Tokens += MyGlobalVariables.TokenChoice;
account.Paid = 1;
dc.Configuration.ValidateOnSaveEnabled = false;
dc.SaveChanges();
}
}
} else if (status < 0)
{
Trace.WriteLine(
"payment error, this is usually final but payments will sometimes be reopened if there was no exchange rate conversion or with seller consent");
} else {
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var account = dc.Users.Where(a => a.Username == MyGlobalVariables.CurrentUser).FirstOrDefault();
if (account != null)
{
account.Paid = 0;
dc.Configuration.ValidateOnSaveEnabled = false;
dc.SaveChanges();
}
}
Trace.WriteLine("Payment is pending");
}
return View();
}
As you can see there are only 3 variables I need to handle.
Also someone might ask why I use Session Variable for Current.User?
Well for some reason Callback method can not read Current.User as it return null. And well... nothing really changed as for now.
If you have ever experienced something like that or can find an issue I would be so thankful since I wasted already over 2 days on that issue.
EDIT:
After some testing I found out variables works fine if I run Post method on my own. So the problem is with handling callback from CoinPayments. Is there a specific way to deal with this?
I am trying to query orders and update them. I have been able to isolate my problem in a unit test:
[Fact(DisplayName = "OrderDocumentRepositoryFixture.Can_UpdateAsync")]
public async void Can_UpdateByQueryableAsync()
{
var order1 = JsonConvert.DeserializeObject<Order>(Order_V20170405_133926_9934934.JSON);
var orderId1 = "Test_1";
order1.Id = orderId1;
await sut.CreateAsync(order1);
foreach (var order in sut.CreateQuery())
{
order.Version = "myversion";
await sut.UpdateAsync(order);
var ordersFromDb = sut.GetByIdAsync(orderId1).Result;
Assert.Equal("myversion", ordersFromDb.Version);
}
}
where :
public IQueryable<T> CreateQuery()
{
return _client.CreateDocumentQuery<T>(UriFactory.CreateDocumentCollectionUri(_databaseId, CollectionId));
}
With this code, orders are not updated.
If I replace the CreateQuery() by what follows, it does work:
[Fact(DisplayName = "OrderDocumentRepositoryFixture.Can_UpdateAsync")]
public async void Can_UpdateByQueryableAsync()
{
var order1 = JsonConvert.DeserializeObject<Order>(Order_V20170405_133926_9934934.JSON);
var orderId1 = "Test_1";
order1.Id = orderId1;
await sut.CreateAsync(order1);
var order = sut.GetByIdAsync(orderId1).Result;
order.Version = "myversion";
await sut.UpdateAsync(order);
var ordersFromDb = sut.GetByIdAsync(orderId1).Result;
Assert.Equal("myversion", ordersFromDb.Version);
}
where
public async Task<T> GetByIdAsync(string id)
{
try
{
var documentUri = UriFactory.CreateDocumentUri(_databaseId, CollectionId, id);
var document = (T) await ((DocumentClient) _client).ReadDocumentAsync<T>(documentUri);
return document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == HttpStatusCode.NotFound) return null;
throw;
}
}
I've been trying to understand why this doesn't work. Obviously i could always do a GetByIdAsync before updating, but that seems overkill?
What can't I see?
Thanks!
You create your query, but you never execute it (CreateDocumentQuery just sets up the query). Try altering your call to something like:
foreach (var order in sut.CreateQuery().ToList())
{
//
}
Also note: if you are always querying for a single document, and you know the id, then ReadDocumentAsync() (your alternate code path) will be much more effecient, RU-wise.
What I am doing currently is adding an item to the Cache and disposing of my object when that object is removed from the Cache. The logic being that it gets removed when memory consumption gets too high. I'm open to outher suggestions but I would like to avoid creating a thread than continually measures memory statistics if possible. Here is my code:
public class WebServiceCache : ConcurrentDictionary<string, WebServiceCacheObject>, IDisposable
{
private WebServiceCache()
{
if (HttpContext.Current != null && HttpContext.Current.Cache != null)
{
HttpContext.Current.Cache.Add("CacheTest", true, null, DateTime.Now.AddYears(1), System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Low,
(key, obj, reason) => {
if (reason != System.Web.Caching.CacheItemRemovedReason.Removed)
{
WebServiceCache.Current.ClearCache(50);
}
});
}
}
private static WebServiceCache _current;
public static WebServiceCache Current
{
get
{
if (_current != null && _current.IsDisposed)
{
// Might as well clear it fully
_current = null;
}
if (_current == null)
{
_current = new WebServiceCache();
}
return _current;
}
}
public void ClearCache(short percentage)
{
try
{
if (percentage == 100)
{
this.Dispose();
return;
}
var oldest = _current.Min(c => c.Value.LastAccessed);
var newest = _current.Max(c => c.Value.LastAccessed);
var difference = (newest - oldest).TotalSeconds;
var deleteBefore = oldest.AddSeconds((difference / 100) * percentage);
// LINQ doesn't seem to work very well on concurrent dictionaries
//var toDelete = _current.Where(c => DateTime.Compare(c.Value.LastAccessed,deleteBefore) < 0);
var keys = _current.Keys.ToArray();
foreach (var key in keys)
{
if (DateTime.Compare(_current[key].LastAccessed, deleteBefore) < 0)
{
WebServiceCacheObject tmp;
_current.TryRemove(key, out tmp);
tmp = null;
}
}
keys = null;
}
catch
{
// If we throw an exception here then we are probably really low on memory
_current = null;
GC.Collect();
}
}
public bool IsDisposed { get; set; }
public void Dispose()
{
this.Clear();
HttpContext.Current.Cache.Remove("CacheTest");
this.IsDisposed = true;
}
}
In Global.asax
void context_Error(object sender, EventArgs e)
{
Exception ex = _context.Server.GetLastError();
if (ex.InnerException is OutOfMemoryException)
{
if (_NgageWebControls.classes.Caching.WebServiceCache.Current != null)
{
_NgageWebControls.classes.Caching.WebServiceCache.Current.ClearCache(100);
}
}
}
Thanks,
Joe
You can access the ASP.NET Cache from anywhere in your application as the static property:
HttpRuntime.Cache
You don't need to be in the context of a Request (i.e. don't need HttpContext.Current) to do this.
So you should be using it instead of rolling your own caching solution.
I'm developing a Win 8 app which needs to do some possibly long running looping and calculations based around the data input by the user. This calculation is run often to update the results in real time.
The calculations are done by a calculator class. I will use example code to give an idea
public class ResultCalculator
{
List<Data> Input1 = new List<Data>();
IQueryable<int> Input2;
IQueryable<Data2> Input3;
public ResultCalculator(List<int> items1, List<Data2> items2)
{
items1.Sort((x,y) => y.CompareTo(x));
Input2 = items1.AsQueryable();
Input3 = items2.AsQueryable().OrderByDescending(w => w.LValue);
}
public void CalculateLValues()
{
foreach (var v in Input3)
{
for (int i = 1; i <= v.Quantity; i++)
{
if (Input1.Count > 0)
{
Data existing = FindExisting(v.LValue, 4);
if (existing != null)
{
existing.Add(v.LValue);
}
else
{
FindNew(v.LValue);
}
}
else
{
FindNew(v.LValue);
}
}
}
OptimisePass1();
}
public void FindNew(int LValue)
{
int options = FindNewItem(LValue, 0);
if (options != 0)
{
Data newdata = new Data(options);
newdata.Add(LValue);
Input1.Add(newdata);
}
}
public void OptimisePass1()
{
foreach (var w in Input1)
{
var ShorterLValues = from sl in Input2 where sl < w.LValue orderby sl select sl;
foreach (var sl in ShorterLValues)
{
if (sl > w.LValue - w.Remaining)
{
w.LValue = sl;
w.CalculateRemaining();
}
}
// MORE CALCULATION TO DO IN ANOTHER LOOP
}
}
public Data FindExisting(int LValueRequired, int additionalvalue)
{
Input1.OrderBy(w => w.LValue);
foreach (var sl in Input1.Where(i => i.Remaining > 0).OrderBy(i => i.Remaining))
{
if (sl.Remaining >= LValueRequired + additionalvalue)
{
return sl;
}
}
return null;
}
public int FindNewItem(int LValueRequired)
{
foreach (var sl in Input2)
{
if (sl >= LValueRequired + 4)
{
return sl;
}
}
return 0;
}
}
This class is the used from my ViewModel as below...
public async Task UpdateCalculationAsync()
{
var data1 = new List<int>(sInput);
var reqlist = new List<Data2>(sInput2);
var lc = new ResultCalculator(data1, data2);
NL.Clear();
await Task.Run(() => lc.CalculateLValues());
foreach (var i in lc.Data1)
{
NL.Add(i);
}
}
Without any async use this held up the UI when it ran if there were many items in the lists. So I added the "await Task.Run(() => lc.CalculateLValues())" to make it run async. I've got a basic grasp of async but not really understood how to properly make my classes run in async. Is this approach correct?
I believe that what I've done hands off the calculation to the background thread. Certainly the UI now remains responsive and can be used whilst the calculation is running. Once the result is calculated my viewmodel gets the result and the UI updates. What I'd really rather have is for my ResultCalculator class to have Task returning methods which I can await. However I'm really struggling on how to refactor for that. I'm not even sure there's a need if this works and is a valid approach. But I'm not 100% convinced it is the proper use of the async pattern and wanted to check if it can be improved?
suggest to do something like this:
// user will do some action on the UI to trigger the compute
public async Task Button1_Click(..)
{
await this.ViewModel.RecalculateAsync();
}
class ViewModel
{
public async Task RecalculateAsync()
{
var data1 = new List<int>(sInput);
var reqlist = new List<Data2>(sInput2);
var lc = new ResultCalculator(data1, data2);
await Task.Run(() => lc.CalculateLValues());
// I am not sure that is NL - if it is items like property on viewmodel that is bound to ListView like control in xaml - that should be fine.
// otherwise, add code here to add the list of result items to an observable collection
// expose this collection as Items property on viewmodel and bind in xaml to ListView.ItemsSource
}
}