Can I use a parameter in a task-based DelegateCommand (Prism.Commands):
(https://prismlibrary.com/docs/commanding.html)
public class ArticleViewModel
{
public DelegateCommand SubmitCommand { get; private set; }
public ArticleViewModel()
{
SubmitCommand = new DelegateCommand<object>(async ()=> await Submit());
}
Task Submit(object parameter)
{
return SomeAsyncMethod(parameter);
}
}
Can I use a parameter in a task-based DelegateCommand?
Sure.
internal class ArticleViewModel : BindableBase
{
public ArticleViewModel()
{
SubmitCommandWithMethodGroup = new DelegateCommand<object>( SomeAsyncMethod );
SubmitCommandWithLambda = new DelegateCommand<object>( async x => { var y = await Something(x); await SomethingElse(y); } );
}
public DelegateCommand<object> SubmitCommandWithMethodGroup { get; }
public DelegateCommand<object> SubmitCommandWithLambda { get; }
}
Related
I have this code that creates a ViewModel for the page. However in the Viewmodel I want to access the property correctButtonPressed but it's not available.
How can I access this?
public partial class PhrasesFrame : Frame
{
public int correctButtonPressed;
public PhrasesFrameViewModel vm = new PhrasesFrameViewModel();
public PhrasesFrame() {
InitializeComponent();
}
private string abc()
{
var a = correctButtonPressed;
}
}
public class PhrasesFrameViewModel : ObservableProperty
{
private ICommand bButtonClickedCommand;
public ICommand BButtonClickedCommand
{
get
{
return bButtonClickedCommand ??
(bButtonClickedCommand = new Command(() =>
{
// Next line gives an error "use expression body for accessors" "use expression body for properties.
correctButtonPressed = 123;
}));
}
}
}
Expose it as a property on the view model and have the view access it.
public partial class PhrasesFrame : Frame {
public PhrasesFrameViewModel vm = new PhrasesFrameViewModel();
public PhrasesFrame() {
InitializeComponent();
}
private string abc() {
//View can access correctButtonPressed via the view model.
var a = vm.correctButtonPressed;
}
}
public class PhrasesFrameViewModel : ObservableProperty {
public int correctButtonPressed;
private ICommand bButtonClickedCommand;
public ICommand BButtonClickedCommand {
get {
return bButtonClickedCommand ??
(bButtonClickedCommand = new Command(() => {
correctButtonPressed = 123;
}));
}
}
}
After updating to ABP v3.0.0, I started getting DbContext disposed exception when running parallel requests to repository that create new UnitOfWork like this:
using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
I looked in the source code and found some code in AsyncLocalCurrentUnitOfWorkProvider that I don't understand. When setting current uow, it sets property in wrapper:
private static readonly AsyncLocal<LocalUowWrapper> AsyncLocalUow = new AsyncLocal<LocalUowWrapper>();
private static void SetCurrentUow(IUnitOfWork value)
{
lock (AsyncLocalUow)
{
if (value == null)
{
if (AsyncLocalUow.Value == null)
{
return;
}
if (AsyncLocalUow.Value.UnitOfWork?.Outer == null)
{
AsyncLocalUow.Value.UnitOfWork = null;
AsyncLocalUow.Value = null;
return;
}
AsyncLocalUow.Value.UnitOfWork = AsyncLocalUow.Value.UnitOfWork.Outer;
}
else
{
if (AsyncLocalUow.Value?.UnitOfWork == null)
{
if (AsyncLocalUow.Value != null)
{
AsyncLocalUow.Value.UnitOfWork = value;
}
AsyncLocalUow.Value = new LocalUowWrapper(value);
return;
}
value.Outer = AsyncLocalUow.Value.UnitOfWork;
AsyncLocalUow.Value.UnitOfWork = value;
}
}
}
private class LocalUowWrapper
{
public IUnitOfWork UnitOfWork { get; set; }
public LocalUowWrapper(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
}
That does not look thread-safe, as any thread can set new UnitOfWork and then dispose it.
Is it a bug? I can use my own implementation of ICurrentUnitOfWorkProvider, without wrapping, but I'm not sure if that is correct.
Update
I can't give an example with DbContext disposed exception, but here is one with null reference exception in repository.GetAll() method. I think it has the same reason.
namespace TestParallelEFRequest
{
public class Ent1 : Entity<int> { public string Name { get; set; } }
public class Ent2 : Entity<int> { public string Name { get; set; } }
public class Ent3 : Entity<int> { public string Name { get; set; } }
public class Ent4 : Entity<int> { public string Name { get; set; } }
public class DomainStartEvent : EventData {}
public class DBContext : AbpDbContext {
public DBContext(): base("Default") {}
public IDbSet<Ent1> Ent1 { get; set; }
public IDbSet<Ent2> Ent2 { get; set; }
public IDbSet<Ent3> Ent3 { get; set; }
public IDbSet<Ent4> Ent4 { get; set; }
}
public class TestService : DomainService, IEventHandler<DomainStartEvent>
{
private readonly IRepository<Ent1> _rep1;
private readonly IRepository<Ent2> _rep2;
private readonly IRepository<Ent3> _rep3;
private readonly IRepository<Ent4> _rep4;
public TestService(IRepository<Ent1> rep1, IRepository<Ent2> rep2, IRepository<Ent3> rep3, IRepository<Ent4> rep4) {
_rep1 = rep1;_rep2 = rep2;_rep3 = rep3;_rep4 = rep4;
}
Task HandleEntityes<T>(IRepository<T> rep, int i) where T : class, IEntity<int> {
return Task.Run(() => {
using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) {
Thread.Sleep(i); // Simulating work
rep.GetAll(); // <- Exception here
}
});
}
public void HandleEvent(DomainStartEvent eventData) {
using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) {
var t1 = HandleEntityes(_rep1, 10);
var t2 = HandleEntityes(_rep2, 10);
var t3 = HandleEntityes(_rep3, 10);
var t4 = HandleEntityes(_rep4, 1000);
Task.WaitAll(t1, t2, t3, t4);
}
}
}
[DependsOn(typeof(AbpEntityFrameworkModule))]
public class ProgrammModule : AbpModule
{
public override void PreInitialize() { Configuration.DefaultNameOrConnectionString = "Default"; }
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
Database.SetInitializer<DBContext>(null);
}
}
class Program {
static void Main(string[] args) {
using (var bootstrapper = AbpBootstrapper.Create<ProgrammModule>()) {
bootstrapper.Initialize();
bootstrapper.IocManager.Resolve<IEventBus>().Trigger(new DomainStartEvent());
Console.ReadKey();
}
}
}
}
I am creating an API for project tasks. It has a TasksController as listed below. I am generating hypermedia using WebApi.Hal and the service supports hal+json and hal+xml media types also.
Following is the response I currently have for the GET request http://localhost:51910/api/tasks/1. In the response there is a list of links for priorities – but they don’t have associated name in the response (to show in the UI – like Low, Medium, High, etc.).
What is the best HAL approach for getting name of the priorities also, using WebApi.HAL?
Note: The list of priorities can be enhanced in the future.
Priority
public class Priority
{
public int PriorityID { get; set; }
public string PriorityName { get; set; }
public string Revision { get; set; }
public DateTime ApprovalDate { get; set; }
}
Controller
public class TasksController : ApiController
{
// GET api/values/5
[HttpGet]
public TaskRepresentation Get(int id)
{
Task selectedTask = TasksHelper.GetTask(id);
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
//PUT For Setting Priority
[HttpPut]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public TaskRepresentation PutSetPriority(int taskID, int priorityID)
{
Task selectedTask = TasksHelper.GetTask(taskID);
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
//Update Task
if (selectedPriority != null)
{
selectedTask.CurrentPriority = selectedPriority.PriorityName;
}
else
{
throw new Exception("Not available");
}
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
[HttpGet]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public Priority Get(int taskID, int priorityID)
{
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
return selectedPriority;
}
}
HAL Generation Related Classes
public static class LinkTemplates
{
public static class TaskLinks
{
public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
}
}
public class TaskRepresentation : Representation
{
Task theTask;
public int TaskID{get{return theTask.TaskID;}}
public string TaskName{get{return theTask.Name;}}
public string CurrentPriority{get{return theTask.CurrentPriority;}}
public string Category{get{return theTask.Category;}}
public TaskRepresentation(Task t)
{
theTask = t;
}
public override string Rel
{
get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Links.Add(LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID }));
}
}
}
HAL Specification mentions title - this will meet the requirement.
Following is the updated response.
{
"TaskID": 1,
"TaskName": "Task1",
"CurrentPriority": "Medium",
"Category": "IT",
"_links": {
"self": {
"href": "/api/tasks/1"
},
"priorities": [
{
"href": "/api/tasks/1/priorities/101",
"title": "Low"
},
{
"href": "/api/tasks/1/priorities/103",
"title": "High"
},
{
"href": "/api/tasks/1/priorities/104",
"title": "Critical"
}
]
}
}
WebAPI.HAL changes
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
lnk.Title = p.PriorityName;
Links.Add(lnk);
}
}
Code
public static class LinkTemplates
{
public static class TaskLinks
{
public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
//public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
public static Link PriorityLink
{
get
{
Link l = new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}");
return l;
}
}
}
}
public class TasksController : ApiController
{
// GET api/values/5
[HttpGet]
public TaskRepresentation Get(int id)
{
Task selectedTask = TasksHelper.GetTask(id);
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
//PUT For Setting Priority
[HttpPut]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public TaskRepresentation PutSetPriority(int taskID, int priorityID)
{
Task selectedTask = TasksHelper.GetTask(taskID);
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
//Update Task
if (selectedPriority != null)
{
selectedTask.CurrentPriority = selectedPriority.PriorityName;
}
else
{
throw new Exception("Not available");
}
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
[HttpGet]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public Priority Get(int taskID, int priorityID)
{
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
return selectedPriority;
}
}
public class TaskRepresentation : Representation
{
Task theTask;
public int TaskID{get{return theTask.TaskID;}}
public string TaskName{get{return theTask.Name;}}
public string CurrentPriority{get{return theTask.CurrentPriority;}}
public string Category{get{return theTask.Category;}}
public TaskRepresentation(Task t)
{
theTask = t;
}
public override string Rel
{
get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
lnk.Title = p.PriorityName;
Links.Add(lnk);
}
}
}
public class Task
{
public string Name { get; set; }
public int TaskID { get; set; }
public string Category { get; set; }
public string CurrentPriority { get; set; }
public List<Priority> PossiblePriorities { get; set; }
}
public class Priority
{
public int PriorityID { get; set; }
public string PriorityName { get; set; }
public string Revision { get; set; }
public DateTime ApprovalDate { get; set; }
}
public static class TasksPrioritiesHelper
{
public static List<Priority> GetAllPriorities()
{
List<Priority> possiblePriorities = new List<Priority>();
Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
Priority pMedium = new Priority { PriorityID = 102, PriorityName = "Medium" };
Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
Priority pCritical = new Priority { PriorityID = 104, PriorityName = "Critical" };
possiblePriorities.Add(pLow);
possiblePriorities.Add(pMedium);
possiblePriorities.Add(pHigh);
possiblePriorities.Add(pCritical);
return possiblePriorities;
}
public static List<Priority> GetAdministrativePriorities()
{
List<Priority> possiblePriorities = new List<Priority>();
Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
possiblePriorities.Add(pLow);
possiblePriorities.Add(pHigh);
return possiblePriorities;
}
public static List<Priority> GetPossiblePrioritiesForTask(Task t)
{
List<Priority> possibleTaskPriorities = new List<Priority>();
if (String.Equals(t.Category, "IT"))
{
possibleTaskPriorities = GetAllPriorities();
}
else
{
possibleTaskPriorities = GetAdministrativePriorities();
}
Priority currentTaskPriority = null;
foreach(Priority p in possibleTaskPriorities )
{
if(String.Equals(t.CurrentPriority,p.PriorityName ))
{
currentTaskPriority=p;
}
}
if(currentTaskPriority!=null)
{
possibleTaskPriorities.Remove(currentTaskPriority);
}
return possibleTaskPriorities;
}
}
public static class TasksHelper
{
public static Task GetTask(int id)
{
Task selectedTask = null;
List<Task> tasks = GetAllTasks();
foreach (Task t in tasks)
{
if(t.TaskID==id)
{
selectedTask = t;
}
}
return selectedTask;
}
public static List<Task> GetAllTasks()
{
List<Task> tasks;
tasks = new List<Task>();
Task t1 = new Task{Category = "IT",CurrentPriority = "Medium",Name = "Task1",TaskID = 1};
t1.PossiblePriorities = TasksPrioritiesHelper.GetPossiblePrioritiesForTask(t1);
tasks.Add(t1);
return tasks;
}
}
In the default AccountController created I see
public AccountController()
: this(Startup.UserManagerFactory(), Startup.OAuthOptions.AccessTokenFormat)
{
}
In Startup.Auth.cs I see
UserManagerFactory = () =>
new UserManager<IdentityUser>(new UserStore<IdentityUser>());
Seems like the implementation of UserStore comes from Microsoft.AspNet.Identity.EntityFramework.
So, to customize the authentication do I have to implement my own version of UserStore like
class MYSTUFFUserStore<IdentityUser> : UserStore<IdentityUser>
{
}
and override the methods and then do this in Startup.Auth.cs
UserManagerFactory = () =>
new UserManager<IdentityUser>(new MYSTUFFUserStore<IdentityUser>());
I am looking for a correct way to customize the authentication.
Assuming your table is called AppUser, convert your own AppUser domain object to IUser(using Microsoft.AspNet.Identity) like this
using Microsoft.AspNet.Identity;
public class AppUser : IUser
{
//Existing database fields
public long AppUserId { get; set; }
public string AppUserName { get; set; }
public string AppPassword { get; set; }
public AppUser()
{
this.Id = Guid.NewGuid().ToString();
}
[Ignore]
public virtual string Id { get; set; }
[Ignore]
public string UserName
{
get
{
return AppUserName;
}
set
{
AppUserName = value;
}
}
}
Implement the UserStore object like this
using Microsoft.AspNet.Identity;
public class UserStoreService
: IUserStore<AppUser>, IUserPasswordStore<AppUser>
{
CompanyDbContext context = new CompanyDbContext();
public Task CreateAsync(AppUser user)
{
throw new NotImplementedException();
}
public Task DeleteAsync(AppUser user)
{
throw new NotImplementedException();
}
public Task<AppUser> FindByIdAsync(string userId)
{
throw new NotImplementedException();
}
public Task<AppUser> FindByNameAsync(string userName)
{
Task<AppUser> task = context.AppUsers.Where(
apu => apu.AppUserName == userName)
.FirstOrDefaultAsync();
return task;
}
public Task UpdateAsync(AppUser user)
{
throw new NotImplementedException();
}
public void Dispose()
{
context.Dispose();
}
public Task<string> GetPasswordHashAsync(AppUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
return Task.FromResult(user.AppPassword);
}
public Task<bool> HasPasswordAsync(AppUser user)
{
return Task.FromResult(user.AppPassword != null);
}
public Task SetPasswordHashAsync(AppUser user, string passwordHash)
{
throw new NotImplementedException();
}
}
If you have your own custom password hashing you will also need to implement IPasswordHasher. Below is an example where there is no hashing of the password(Oh no!)
using Microsoft.AspNet.Identity;
public class MyPasswordHasher : IPasswordHasher
{
public string HashPassword(string password)
{
return password;
}
public PasswordVerificationResult VerifyHashedPassword
(string hashedPassword, string providedPassword)
{
if (hashedPassword == HashPassword(providedPassword))
return PasswordVerificationResult.Success;
else
return PasswordVerificationResult.Failed;
}
}
In Startup.Auth.cs replace
UserManagerFactory = () =>
new UserManager<IdentityUser>(new UserStore<IdentityUser>());
with
UserManagerFactory = () =>
new UserManager<AppUser>(new UserStoreService()) { PasswordHasher = new MyPasswordHasher() };
In ApplicationOAuthProvider.cs, replace IdentityUser with AppUser
In AccountController.cs, replace IdentityUser with AppUser and delete all the external authentication methods like GetManageInfo and RegisterExternal etc.
ActionBase, ActionA, ActionB and ActionC are Entities (from a database). ActionA, ActionB and ActionC are derived type of ActionBase.
ActionB and ActionC implements ISpecialAction with a SpecialProperty.
ex :
public interface ISpecialAction
{
Guid SpecialProperty { get; }
}
public partial class ActionBase
{
public objectX OnePropertyBase { get; set; }
}
public partial class ActionA : ActionBase
{
public objectY OnePropertyA { get; set; }
}
public partial class ActionB:ActionBase,ISpecialAction
{
public objectZ OnePropertyB { get; set; }
public Guid SpecialProperty
{
get
{
return OnePropertyB.ID;
}
}
}
public partial class ActionC : ActionBase ,ISpecialAction
{
public objectW OnePropertyC { get; set; }
public Guid SpecialProperty
{
get
{
return OnePropertyC.ID;
}
}
}
My problem is that SpecialProperty is build from other Properties of the objects (ActionB or ActionC) and when the cast (to ISpecialAction) is done, OtherProperty and OtherProperty2 are null.
I tried :
GetActionBase().ToList().Where(x=>x is ISpecialAction && ((dynamic) x).SpecialProperty== p_SpecialProperty);
GetActionBase().ToList().Where(x=>x is ISpecialAction && ((ISpecialAction) x).SpecialProperty== p_SpecialProperty);
GetActionBase().ToList().OfType<ISpecialAction>().Where(x => x.SpecialProperty== p_SpecialProperty).Cast<ActionBase>();
return GetActionOnGoing().ToList().OfType<ICityAction>().Cast<ActionBase>().Where(x => ((dynamic)x).CityId == p_CityId);
remark : OfType<> doesn't works with an Interface in Linq to entities but is ok in Linq to object
How do I access my property interface without knowing the type of the object?
I might missed something but this is Ok with the code you provided :
public class objectX
{
}
public class objectY
{
}
public class objectZ
{
public Guid ID { get { return Guid.NewGuid();} }
}
public class objectW
{
public Guid ID { get { return new Guid(); } }
}
class Program
{
private static Guid p_SpecialProperty;
static void Main(string[] args)
{
var result = GetActionBase().ToList().Where(x => x is ISpecialAction && ((dynamic)x).SpecialProperty == p_SpecialProperty).FirstOrDefault();
var result1 = GetActionBase().ToList().Where(x => x is ISpecialAction && ((ISpecialAction)x).SpecialProperty == p_SpecialProperty).FirstOrDefault();
var result2 = GetActionBase().ToList().OfType<ISpecialAction>().Where(x => x.SpecialProperty == p_SpecialProperty).Cast<ActionBase>().FirstOrDefault();
}
private static IEnumerable<ActionBase> GetActionBase()
{
return new List<ActionBase> {new ActionA{OnePropertyA= new objectY()}, new ActionB{OnePropertyB=new objectZ()},new ActionC{OnePropertyC=new objectW()} };
}
}
Not sure if I exactly understand your question, but could you try using an intermediate interface, such as:
public interface ISpecialActionB : ISpecialAction
{
objectZ OnePropertyB { get; set; }
}
public class ActionB : ActionBase, ISpecialActionB
{
//same stuff
}
and casting to that instead.
var b = new ActionB{OnePropertyB = new Whatever()};
var bAsSpecial = b as ISpecialActionB;
var whatever = b.OnePropertyB; // should not be null
It' ok.
Your example run very well without problem so I searched in a other way : AutoMapper.
l_List.Actions = Mapper.Map<List<ActionBase>, Action[]>(l_ActionManagement.GetActionBySpecialId(l_Special.ID).ToList());
The problem was not interfaces or Linq queries but it was that automapper need an empty constructor and in this constructor, I need to initialize OnePropertyB and OnePropertyC to compute SpecialProperty.
Thanks