Here is a piece of code, where I try to execute different async methods, that need to be executed in specific order (the await, and Task.WhenAll() parts).
//Some other tasks before
Task<bool> taskIfcQuantityArea = Task.Run<bool>(() =>
{
return this.addGroupStringToDictionary("IfcQuantityArea");
});
Task<bool> taskIfcQuantityLength = Task.Run<bool>(() =>
{
return this.addGroupStringToDictionary("IfcQuantityLength");
});
Task<bool> taskIfcSiUnit = Task.Run<bool>(() =>
{
return addGroupStringToDictionary("IfcSiUnit");
});
Task<bool> taskIfcPropertySingleValue = Task.Run<bool>(() =>
{
return addGroupStringToDictionary("IfcPropertySingleValue");
});
//uses IfcPerson, IfcOrganization
Task<bool> taskIfcPersonAndOrganization = Task.Run<bool>(() =>
{
return addGroupStringToDictionary("IfcPersonAndOrganization");
});
//uses IfcOrganization
Task<bool> taskIfcApplication = Task.Run(async () =>
{
await taskIfcSiUnit;
return addGroupStringToDictionary("IfcApplication");
});
//uses IfcSiUnit
Task<bool> taskIfcMeasureWithUnit = Task.Run(async () =>
{
await taskIfcSiUnit;
return addGroupStringToDictionary("IfcMeasureWithUnit");
});
//some other tasks after.
When I do that job synchronously, all works fine, but when I do it in async, I have some random errors. At every test, the errors come randomly.
The only thing I see that could go wrong, is they all execute the same function addGroupStringToDictionary.
Here is the function :
private bool addGroupStringToDictionary(string typeName)
{
//int processCount = await Task.Run<int>(() =>
//{
GroupedListStrings groupElt = this.listGrouppedStrings.FirstOrDefault(x => x.Type == typeName.ToUpper());
if (groupElt != null)
{
List<string> listStringInGroup = groupElt.ListStrings;
foreach (string line in listStringInGroup)
{
try
{
if(typeName== "IfcLocalPlacement($")
{
typeName = "IfcLocalPlacement";
}
var type = Type.GetType("Ifc."+typeName);
if (typeName == "IfcPropertySingleValue" || typeName == "IfcDirection" || typeName == "IfcSiUnit" || typeName == "IfcQuantityLength" || typeName == "IfcQuantityArea" || typeName == "IfcQuantityVolume" || typeName == "IfcQuantityWeight")
{
try
{
object instance = Activator.CreateInstance(type, line);
this.addToListDictionary((IfcElement)instance);
}
catch
{
}
}
else if (typeName == "IfcOpeningElement")
{
try
{
object instance = Activator.CreateInstance(type, line, this.listDictionaries, this.DictionaryBolts);
this.addToListDictionary((IfcElement)instance);
}
catch
{
}
}
else
{
try
{
object instance = Activator.CreateInstance(type, line, this.listDictionaries);
this.addToListDictionary((IfcElement)instance);
}
catch
{
}
}
}
catch
{
this.addError(line);
}
}
this.listGrouppedStrings.Remove(groupElt);
this.reportProgressImport();
}
//return 100;
//});
this.reportProgressImport();
return true;
}
The catch got 1-2 times over a bit more than 1 million lines.
At each test the errors come randomly.
Is it possible that running the function simultaneously from several async methods, this is what causes the problem?
Here is the addToListDictionary function :
private void addToListDictionary(IfcElement elt)
{
if(elt.ErrorFound)
{
this.listReadButError.Add(elt);
return;
}
string type = elt.GetType().ToString();
if (elt is IfcRepere)
{
type = "Ifc.IfcRepere";
}
else if (elt is IfcRepereType)
{
type = "Ifc.IfcRepereType";
}
else if (elt is IfcPhysicalSimpleQuantity)
{
type = "Ifc.IfcPhysicalSimpleQuantity";
}
else if (elt is IfcProfileDef)
{
type = "Ifc.IfcProfileDef";
}
else if (elt is IfcGeometricRepresentationContext)
{
type = "Ifc.IfcGeometricRepresentationContext";
}
GroupDictionary group = this.ListDictionaries.FirstOrDefault(x => x.Name == type);
if(group==null)
{
group = new GroupDictionary { Name = type };
this.ListDictionaries.Add(group);
}
group.ListElements[elt.ID] = elt;
if (elt is IfcMechanicalFastener)
{
IfcMechanicalFastener bolt = (IfcMechanicalFastener)elt;
this.DictionaryBolts[bolt.Tag] = bolt;
}
else if(elt is IfcProject)
{
this.listProjects.Add((IfcProject)elt);
}
else if(elt is IfcElementAssembly ifcAss)
{
this.DictionaryIfcElementAssemblies[ifcAss.Key] = ifcAss;
}
}
Also some additive information about my ListDictionaries :
private List<GroupDictionary> listDictionaries = new List<GroupDictionary>();
public List<GroupDictionary> ListDictionaries { get { return this.listDictionaries; } set { this.listDictionaries = value; } }
And the class GroupDictionary
public class GroupDictionary
{
string name { get; set; }
public string Name { get { return this.name; } set { this.name = value; } }
public ConcurrentDictionary<int, IfcElement> ListElements = new ConcurrentDictionary<int, IfcElement>();
public GroupDictionary()
{
}
}
I made different GroupDictionary because as soon as I don't need one of them, I delete it to free space.
I have one dictionary with IfcPoint, I need it to gt IfcPolyLine (lines), but when I finish to treat all objects using IfcPoint, I clear remove the corresponding GroupDictionary in order to free some memory.
You have a obvious thread-safety issues here (i.e. you are trying to perform some operation which is not thread safe from multiple threads at a time). There are multiple ways you can try tackling it - using locks, or some synchronization primitives.
But in this case it seems that major source of issues is working with standard collections from multiple threads, which is not thread-safe (because thread-safety usually comes with performance price and is not always needed). You can start from switching to appropriate collections from System.Collections.Concurrent namespace.
To go down deeper I recommend free e-book by Joseph Albahari Threading in C#.
Related
I have a method that takes a context and entity object as parameters.
This method should be able to determine if a common property (COID in my code) of any class(table) has a value.
I can't find a way to rewrite this code so it is more generic, and at the moment I am checking the type of each entity passed to the method.
public async static Task<bool> IsCOIDAssigned(ProjectEntities _context, object _entity)
{
var bSuccess = false;
//First type to check
if (_entity is tblLine)
{
var _line = _entity as tblLine;
await _context.Entry(_entity).ReloadAsync().ContinueWith(x =>
{
if (!x.IsFaulted)
{
var query = from c in _context.tblLines
where c.ID.Equals(_line.ID)
select c;
if(query.Single().COID.GetValueOrDefault() == 0)
{
Console.WriteLine("Not assigned");
bSuccess = true;
}
else
{
Console.WriteLine("Assigned");
bSuccess = false;
}
}
else
{
bSuccess = false;
}
}, TaskScheduler.FromCurrentSynchronizationContext());
};
//Second type to check
if (_entity is tblDevice)
{
var _device = _entity as tblDevice;
await _context.Entry(_entity).ReloadAsync().ContinueWith(x =>
{
if (!x.IsFaulted)
{
var query = from c in _context.tblDevices
where c.ID.Equals(_device.ID)
select c;
if (query.Single().COID.GetValueOrDefault() == 0)
{
Console.WriteLine("Not assigned");
bSuccess = true;
}
else
{
Console.WriteLine("Assigned");
bSuccess = false;
}
}
else
{
bSuccess = false;
}
}, TaskScheduler.FromCurrentSynchronizationContext());
};
//Third type to check ....
//Fourth type to check ....
return bSuccess;
}
Does anyone see a better solution to the problem?
I followed arekzyla's solution to make my tables inheret tblBase.
However, since I have a database-first model it was not possible to modify my model through code (not sure if this is possible?)
I managed to get what I was looking for thanks to arekzyla, but with less linq queries involved, I am casting my entities as TblBase which is a class containing ID and COID (common table properties.)
public static async Task<bool> IsEntityCheckedOut(ProjectEntities _context, object _entity)
{
var bCheckedOut = false;
await _context.Entry(_entity).ReloadAsync().ContinueWith(x =>
{
if (!x.IsFaulted)
{
var _baseentity = _entity as TblBase;
if (_baseentity.COID.GetValueOrDefault() != 0)
{
Console.WriteLine("Assigned");
bCheckedOut = true;
}
else
{
Console.WriteLine("Not Assigned");
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
return bCheckedOut;
}
You can make base abstract class for both tblLine and tblDevice containing at least properties COID and Id.
public abstract class TblBase
{
public int Id { get; set; }
public int COID { get; set; }
//other common properties
}
public class TblLine : TblBase
{
// properties
}
public class TblDevice : TblBase
{
// properties
}
So in your context you will have:
public DbSet<TblBase> TblBases { get; set; }
You have to set inheritance to TPC (Table-per-Concrete-Type) for both classes:
modelBuilder.Entity<TblLine>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("tblLines");
});
modelBuilder.Entity<TblDevice>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("tblDevices");
});
Then you can use context.TblBases to query data.
I am gettin an null reference exception inside the Controller on the line:
return await Store.GetSearchDTO();
The error in the console reads:
POST http://localhost:55471/api/GetSearchDTO 500 (Internal Server Error)
Error: Resolving failed with a reason [object Object], but no resolveFailed provided for segment Search
Any insight on why this may be happening would be great.
Controller
namespace Api.Controllers
{
[Authorize]
[RoutePrefix("api/Search")]
public class Controller : ApiController
{
private Store _store;
public Store Store
{
get
{
return _store ?? Request.GetOwinContext().Get<Store>();
}
private set
{
_store = value;
}
}
public Controller()
{
}
public Controller(Store store)
{
Store = store;
}
[HttpPost]
[Route("GetSearchDTO")]
public async Task<SearchDTO> GetSearchDTO()
{
return await Store.GetSearchDTO();
}
}
}
Store
public async Task<SearchDTO> GetSearchDTO()
{
var toReturn = new SearchDTO();
var assessment = await Db.Definitions.Where(x => x.IsActive == true).ToListAsync();
var Types = await Db.Types.ToListAsync();
int i = 0;
int j = 0;
foreach(var assess in assessment)
{
var courseName = await Db.Courses.Where(x => x.Id == assess.CourseId).FirstOrDefaultAsync();
toReturn.CourseIds[i] = courseName.Id;
toReturn.CourseNames[i] = courseName.Name;
toReturn.Names[i] = assess.Name;
i++;
}
foreach(var type in Types)
{
toReturn.TypeIds[j] = type.Id;
toReturn.Types[j] = type.Name;
}
toReturn.SectionFlag = true;
return toReturn;
}
}
}
I have a WPF application.
The data is brought from the repository to the ViewModel. What would be the better way to retrieve the data:
Method 1:
In Repository:
public List<LogDetail> GetLogsOfTypeForCase(int caseId, LoggType logType)
{
using (var ctx = new SidraEntitiesNoChangesDetection())
{
var logs = (from l in ctx.Loggs
where l.log_fk_caseid == caseId && l.log_operation == logType.ToString()
select new LogDetail()
{
ColumnName = l.log_columnname,
DateAndTime = l.log_dateandtime,
IdentificationDetail = l.log_identificationDetail,
NewValue = l.log_new_value,
OldValue = l.log_old_value,
TableName = l.log_tablename,
UserCode = l.User.usr_code
}).ToList();
return logs;
}
}
In ViewModel:
await Task.Run(
() =>
{
if (false == this.CancellationTokenSource.IsCancellationRequested)
{
this.CaseLogs = this.dataAdapter.GetLogsOfTypeForCase(this.CaseId, LoggType.S);
}
},
this.CancellationTokenSource.Token
);
or
Method 2
In Repository:
public async Task<List<LogDetail>> GetLogsOfTypeForCase(int caseId, LoggType logType)
{
using (var ctx = new SidraEntitiesNoChangesDetection())
{
var logs = await (from l in ctx.Loggs
where l.log_fk_caseid == caseId && l.log_operation == logType.ToString()
select new LogDetail()
{
ColumnName = l.log_columnname,
DateAndTime = l.log_dateandtime,
IdentificationDetail = l.log_identificationDetail,
NewValue = l.log_new_value,
OldValue = l.log_old_value,
TableName = l.log_tablename,
UserCode = l.User.usr_code
}).ToListAsync();
return logs;
}
}
and in ViewModel
protected override async void Load()
{
if (false == this.CancellationTokenSource.IsCancellationRequested)
{
this.CaseLogs = await this.dataAdapter.GetLogsOfTypeForCase(this.CaseId, LoggType.S);
}
}
From what I have read, Method 1 would be preferred, but what be the advantages?
Method 2 is preferable, because it uses one less thread.
It also can (with some modifications) properly support cancellation:
public async Task<List<LogDetail>> GetLogsOfTypeForCase(int caseId, LoggType logType, CancellationToken token)
{
...
}).ToListAsync(token);
...
}
protected override async void Load()
{
this.CaseLogs = await this.dataAdapter.GetLogsOfTypeForCase(this.CaseId, LoggType.S, this.CancellationTokenSource.Token);
}
Method 2. The Async versions of these methods do all the "heavy lifting" for you, that was what they were designed for. Task.Run() is a heavy process call, you are required to handle all the potential errors and failures yourself, you don't need a sledge hammer here, just a light weight finishing hammer.
By this I mean that you are trying to create what the framework has already done for you, this is where Async calls were meant to be used so why not just use them?
The scenario (WPF desktop app, .NET 4.6):
I have a listbox which display some "tasks".
The goal is to start an asynchronous process that will iterate through all tasks, executing each one of them.
It is a long running process so the desired behavior is to disable most of the commands without locking the UI so the user can still cancel it.
It should flag each tasks as it goes (stand by, running, complete) so the UI can be dynamically updated providing feedback to end user (using styles based on the "Status" enum).
The Problem
When the command (ExecuteTasks) is executed I get the message:
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
My question is: how can I get around this problem using ReactiveUI? I believe the answer is somewhere around schedulers but I couldn't figure it out so far.
Here is what the code looks like:
public ReactiveCommand<object> AddTask { get; }
public ReactiveCommand<object> ExecuteTasks { get; }
public IPlugin SelectedTask
{
get { return selectedTask; }
set { this.RaiseAndSetIfChanged(ref selectedTask, value); }
}
public ReactiveList<IPlugin> Tasks
{
get { return tasks; }
}
public ReactiveList<PluginFactoryGroup> TaskFactories
{
get
{
return taskFactories;
}
}
public AppViewModel(IExecutionContext context, IEnumerable<PluginFactoryGroup> taskFactories)
{
this.context = context;
// initialize lists
tasks = new ReactiveList<IPlugin>() { ChangeTrackingEnabled = true };
this.taskFactories = new ReactiveList<PluginFactoryGroup>(taskFactories);
// create observables to determine whether or not commands can be executed
var canEdit = /*...*/
var canExecute = /*...*/
// initialize commands
AddTask = ReactiveCommand.Create(canEdit);
AddTask.Subscribe(_ => {
if (SelectedFactory != null)
{
var t = SelectedFactory.Create(this.context);
Tasks.Add(t);
SelectedTask = t;
}
});
ExecuteTasks = ReactiveCommand.CreateAsyncTask(canExecute, _ =>
{
return Task.Run(() =>
{
object result = null;
foreach (var item in Tasks)
{
item.Clear();
item.Validate();
}
if (Tasks.Any(e => e.Status == TaskStatus.Error))
{
Tasks.Reset();
return result;
}
foreach (var item in Tasks)
{
item.Status = XrmTools.Plugins.TaskStatus.Running;
item.Execute();
item.Status = XrmTools.Plugins.TaskStatus.Completed;
}
return result;
});
});
}
All UI updates (ReactiveList add/remove, or IPlugin property change) need to happen in UI thread. In your case, assuming item.Execute() is the lengthy operation you want to happen in the background, you should use async/await instead of Task.Run, e.g: your code should look like:
ExecuteTasks = ReactiveCommand.CreateAsyncTask(canExecute, async _ =>
{
object result = null;
foreach (var item in Tasks)
{
item.Clear();
item.Validate();
}
if (Tasks.Any(e => e.Status == TaskStatus.Error))
{
Tasks.Reset();
return result;
}
foreach (var item in Tasks)
{
item.Status = XrmTools.Plugins.TaskStatus.Running;
await ExecuteAsync(item);
item.Status = XrmTools.Plugins.TaskStatus.Completed;
}
return result;
});
Task ExecuteAsync(IPlugin item)
{
return Task.Run(() => item.Execute());
}
Have a look at this reference if you need more inspiration.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace Crystal_Message
{
class Message
{
private int messageID;
private string message;
private ConcurrentBag <Employee> messageFor;
private Person messageFrom;
private string calltype;
public Message(int iden,string message, Person messageFrom, string calltype, string telephone)
{
this.messageID = iden;
this.messageFor = new ConcurrentBag<Employee>();
this.Note = message;
this.MessageFrom = messageFrom;
this.CallType = calltype;
}
public ConcurrentBag<Employee> ReturnMessageFor
{
get
{
return messageFor;
}
}
public int MessageIdentification
{
get { return this.messageID; }
private set
{
if(value == 0)
{
throw new ArgumentNullException("Must have Message ID");
}
this.messageID = value;
}
}
public string Note
{
get { return message; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Must Have a Message");
}
this.message = value;
}
}
public Person MessageFrom
{
get { return messageFrom; }
private set
{
this.messageFrom = value;
}
}
public string CallType
{
get { return this.calltype; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentNullException("Please specify call type");
}
this.calltype = value;
}
}
public void addEmployee(Employee add)
{
messageFor.Add(add);
}
public override string ToString()
{
return "Message: " + this.message + " From: " + this.messageFrom + " Call Type: " + this.calltype + " For: " + this.returnMessagefor();
}
private string returnMessagefor()
{
string generate="";
foreach(Employee view in messageFor)
{
generate += view.ToString() + " ";
}
return generate;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
Message testEquals = obj as Message;
if((System.Object)testEquals == null)
{
return false;
}
return (this.messageID == testEquals.messageID) && (this.message == testEquals.message) && (this.messageFor == testEquals.messageFor) && (this.messageFrom == testEquals.messageFrom) && (this.calltype == testEquals.calltype);
}
public bool Equals(Message p)
{
if ((Object)p == null)
{
return false;
}
return (this.messageID == p.messageID) && (this.message == p.message) && (this.messageFor == p.messageFor) && (this.messageFrom == p.messageFrom) && (this.calltype == p.calltype);
}
public override int GetHashCode()
{
unchecked
{
return this.messageID.GetHashCode() * 33 ^ this.message.GetHashCode() * 33 ^ this.messageFor.GetHashCode() * 33 ^ this.messageFrom.GetHashCode() * 33 ^ this.calltype.GetHashCode();
}
}
}
}
I have a Message class where a user could leave a message for more than one person. I have a getter for it, however, is returning a ConcurrentBag<> the way I've done proper practice? If not, how do i return the ConcurrentBag<> so I can loop through it and display it?
ConcurrentBag<T> is an IEnumerable<T>. You can loop through it as usual. However, as this is a thread safe collection, there are performance concerns to using it.
If you want to get rid of the performance impact while looping, call ToArray on it and return the new array instead.
public IEnumerable<Employee> ReturnMessageFor
{
get
{
return messageFor.ToArray();
}
}
It's not clear to me what you are trying to accomplish.
Are you trying to externalize the Bag for all operations? Because that's what you did...
If you want to externalize something you can iterate over you should either return the Bag as IEnumerable or return an array or a list copied from the Bag.
Either way it's safe to iterate over. Might not be the best in terms of performance, but that's another question.
// Option 1
public IEnumerable<Employee> ReturnMessageFor
{
get
{
return messageFor;
}
}
// Option 2
public Employee[] ReturnMessageFor
{
get
{
return messageFor.ToArray();
}
}
Notes:
You might want to make messageFor readonly (in the code you posted it is readonly).
Remember that a ConcurrentBag allows you to safely iterate over a snapshot of the collection in a thread safe manner, but it does not lock the items in the collection.