I'm using the ASP.NET Boilerplate for my project. And I have an entity as shown in the code snippet below.
public class Transaction : FullAuditedEntity<Guid>, IMustHaveTenant
{
protected Transaction()
{
TransactionState = TransactionState.Uncompleted;
}
public TransactionState TransactionState { get; protected set; }
public virtual Loan Loan { get; protected set; }
public int TenantId { get; set; }
// ...
public async Task CompleteAsync(ICoreBankingService coreBankingService, IRepository<Transaction, Guid> transactionRepository)
{
try
{
// Perform a series of compulsory actions in some given sequence with coreBankingService that might throw exception
Loan.SetSomeStuffThatOriginatedFromMotherTransaction();
TransactionState = TransactionState.Completed;
}
catch (Exception ex)
{
// Log the exception and set this Transaction entity state appropriately
TransactionState = TransactionState.Failed;
}
finally
{
// Make sure by all means to persist the resulting the entity within itself
await transactionRepository.UpdateAsync(this);
}
}
}
I understand I should separate persistence from the entity (which by the way, is an architecture provided by ASP.NET Boilerplate out of the box! using Application Services).
However, I NEED to make certain that I perform a series of compulsory actions in some given sequence with coreBankingService and persist changes at each stage of these computations on the Transaction entity, hence the reason for my naive and probably wrong approach.
Please, what is the right approach to this kind of problem? How do I persist states of an entity that results from a computation or action within the same entity?
You can expose internal methods that change the state:
public class Transaction : FullAuditedEntity<Guid>, IMustHaveTenant
{
protected Transaction()
{
TransactionState = TransactionState.Uncompleted;
}
public TransactionState TransactionState { get; protected set; }
public virtual Loan Loan { get; protected set; }
// ...
internal void Abort()
{
TransactionState = TransactionState.Failed;
}
internal void Complete()
{
TransactionState = TransactionState.Completed;
}
}
And define the domain service in the same assembly:
public class TransactionManager : DomainService
{
private readonly ICoreBankingService _coreBankingService;
private readonly LoanManager _loanManager;
private readonly IRepository<Transaction, Guid> _transactionRepository;
public TransactionManager(
ICoreBankingService coreBankingService,
LoanManager loanManager,
IRepository<Transaction, Guid> transactionRepository)
{
_coreBankingService = coreBankingService;
_loanManager = loanManager;
_transactionRepository = transactionRepository;
}
public async Task TryCompleteAsync(Transaction transaction)
{
try
{
// Use _coreBankingService to do something that might throw exception
_coreBankingService.DoSomething();
_loanManager.SetSomeStuffThatOriginatedFromMotherTransaction(transaction.Loan);
transaction.Complete();
}
catch (Exception ex)
{
// Log the exception and abort the Transaction
transaction.Abort();
}
finally
{
// Make sure by all means to persist the resulting the entity
await _transactionRepository.UpdateAsync(transaction);
}
}
}
Usage:
await _transactionManager.TryCompleteAsync(transaction);
Related
I use library MediatR in my ASP.NET Core application.
I have the following entity Ad:
public class Ad
{
public Guid AdId { get; set; }
public AdType AdType { get; set; }
public double Cost { get; set; }
public string Content { get; set; }
// ...
}
public enum AdType
{
TextAd,
HtmlAd,
BannerAd,
VideoAd
}
I want to introduce the ability to create a new ad. To do so, I've created the following command:
public class CreateAdCommand : IRequest<Guid>
{
public AdType AdType { get; set; }
public double Cost { get; set; }
public string Content { get; set; }
public class Handler : IRequestHandler<CreateAdCommand, Guid>
{
private readonly MyDbContext _context;
public Handler(MyDbContext context)
{
_context = context;
}
public async Task<Guid> Handle(CreateAdCommand request, CancellationToken cancellationToken)
{
var ad = new Ad {AdType = request.AdType, Cost = request.Cost, Content = request.Content};
_context.Ads.Add(ad);
_context.SaveChangesAsync();
return ad.AdId;
}
}
}
This code works great. But here is a huge problem: each ad-type has some additional logic to the ad creation process (e.g., when creating the ad of type TextAd we need to find the keywords in the content of the ad). The simplest solution is:
public async Task<Guid> Handle(CreateAdCommand request, CancellationToken cancellationToken)
{
var ad = new Ad {AdType = request.AdType, Cost = request.Cost, Content = request.Content};
_context.Ads.Add(ad);
_context.SaveChangesAsync();
switch (request.AdType)
{
case AdType.TextAd:
// Some additional logic here...
break;
case AdType.HtmlAd:
// Some additional logic here...
break;
case AdType.BannerAd:
// Some additional logic here...
break;
case AdType.VideoAd:
// Some additional logic here...
break;
}
return ad.AdId;
}
This solution violates the Open Closed Principle (when I create a new ad-type, I need to create a new case inside of CreateAdCommand).
I have another idea. I can create a separate command for each ad-type (e.g., CreateTextAdCommand, CreateHtmlAdCommand, CreateBannerAdCommand, CreateVideoAdCommand). This solution follows the Open Closed Principle (when I create a new ad-type, I need to create a new command for this ad-type - I don't need to change the existing code).
public class CreateTextAdCommand : IRequest<Guid>
{
public double Cost { get; set; }
public string Content { get; set; }
public class Handler : IRequestHandler<CreateTextAdCommand, Guid>
{
private readonly MyDbContext _context;
public Handler(MyDbContext context)
{
_context = context;
}
public async Task<Guid> Handle(CreateTextAdCommand request, CancellationToken cancellationToken)
{
var ad = new Ad {AdType = AdType.TextAd, Cost = request.Cost, Content = request.Content};
_context.Ads.Add(ad);
await _context.SaveChangesAsync();
// Some additional logic here ...
return ad.AdId;
}
}
}
public class CreateHtmlAdCommand : IRequest<Guid>
{
public double Cost { get; set; }
public string Content { get; set; }
public class Handler : IRequestHandler<CreateHtmlAdCommand, Guid>
{
private readonly MyDbContext _context;
public Handler(MyDbContext context)
{
_context = context;
}
public async Task<Guid> Handle(CreateHtmlAdCommand request, CancellationToken cancellationToken)
{
var ad = new Ad {AdType = AdType.HtmlAd, Cost = request.Cost, Content = request.Content};
_context.Ads.Add(ad);
await _context.SaveChangesAsync();
// Some additional logic here ...
return ad.AdId;
}
}
}
// The same for CreateBannerAdCommand and CreateVideoAdCommand.
This solution follows the Open Closed Principle, but violates the DRY principle. How can I solve this problem?
If you stick to your second approach, you can levarage MediatR 'Behaviors' (https://github.com/jbogard/MediatR/wiki/Behaviors). They act like pipelines, where you can offload common behavior into a commonly used handler.
To do this, create a marker interface
interface ICreateAdCommand {}
Now let each concreate command inherit from it
public class CreateTextAdCommand : ICreateAdCommand
{
public readonly string AdType {get;} = AdType.Text
}
public class CreateHtmltAdCommand : ICreateAdCommand
{
public readonly string AdType {get;} = AdType.Html
}
/*...*/
You could combine this or replace this with a common abstract base class, to avoid repetition of common properties. This is up to you.
Now we create the handler for our behavior:
public class CreateAdBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TReq : ICreateAdCommand
{
public CreateAdBehavior()
{
//wire up dependencies.
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var ad = new Ad {AdType = request.AdType, Cost = request.Cost, Content = request.Content};
_context.Ads.Add(ad);
await _context.SaveChangesAsync();
//go on with the next step in the pipeline
var response = await next();
return response;
}
}
Now wire up this behavior. In asp.net core this would be in your startup.cs
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CreateAdBehavior<,>));
At this stage, everytime any of your IRequests implement ICreateAdCommand, it would automatically call the handler above and after this is done it would call the next behavior in line, or if there is none, the actual handler.
Your specific handler for, let's say a HtmlAd would now roughly look like this:
public class CreateHtmlAdCommand : IRequest<Guid>
{
public class Handler : IRequestHandler<CreateHtmlAdCommand, Guid>
{
private readonly MyDbContext _context;
public Handler(MyDbContext context)
{
_context = context;
}
public async Task<Guid> Handle(CreateHtmlAdCommand request, CancellationToken cancellationToken)
{
// Some additional logic here ...
}
}
}
** Update **
If you want to drag data across the pipeline, you can leverage the actual request object.
public abstract class IRequestWithItems
{
public IDictionary<string, object> Items {get;} = new Dictionary<string,object>();
}
Now in your CreateAdBehavior, you can create your ad and store it in the dictionary, to retrieve it in the next handler:
var ad = { ... }
await _context.SaveChangesAsync();
items["newlyCreatedAd"] = ad;
And in the actual Task<Guid> Handle() method, you have now the ad at your disposal, without looping back to your database to retrieve it again.
Details from the author: https://jimmybogard.com/sharing-context-in-mediatr-pipelines/
I am trying to implement a Policy that is quite granular level.
The idea is like in the image.
Each entity has always the One-To-Many relation with the entity on the right.
One Institution can have many Courses, each Course can have many Subjects, each Subject can have many Syllabus, etc...
There are 3 Roles: Administrator, Contributor, Viewer
If you have a Role in one of the top entities this role will be propagated to the rest bellow.
E.g: If you are an Administrator of Course you are administrator of Subject, Syllabus, etc...
If you are Contributor of one of the Syllabus you will be Contributor for bellow Lessons and Videos of this Syllabus.
I have tried to solve it using Custom Policies:
Adding a requirement like below:
public class AdministratorRequirement : IAuthorizationRequirement
{
public int UserId { get; private set; }
public EntityType EntityType { get; private set; }
public int EntityId { get; private set; }
public AdministratorRequirement(int userId, EntityType entityType, int entityId)
{
UserId = userId;
EntityType = entityType;
EntityId = entityId;
}
}
And adding the Policy Handler as bellow:
public class AdministratorHandler : AuthorizationHandler<AdministratorRequirement>
{
public IRolesRepository RolesRepository {get;set;}
public AdministratorHandler(IRolesRepository rolesRepository)
{
RolesRepository = rolesRepository;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdministratorRequirement requirement)
{
// Save User object to access claims
bool isAdministrator = RolesRepository.CheckUserRole(requirement.UserId, requirement.EntityType, requirement.EntityId, "Administrator");
if (isAdministrator)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
The problem is that I would like to define variable requirement on the Startup class:
options.AddPolicy("CourseAdministrator",
policy => policy
.Requirements
.Add(
new AdministratorRequirement(
/*userId - should be variable*/ 0,
EntityType.Course,
/*int entityId - should be variable*/ 0))
And use it on something like
[Authorize(/*pass some parameters in here like user Id and course Id*/)]
[HttpPost]
[Route("create")]
public async Task<IActionResult> CreateCourse([FromBody] Course course)
{
//Or call the policy handler programatically in here.
CleanCacheOnUpdateCourse();
return Ok(await Services.CreateCourse(course, EmauaUser));
}
Do you know if there is such a solution?
For Policy, you need to pass the satic variable.
If you want to check the permission dynamically, you could implement your own IAuthorizationFilter like
custom IAuthorizationFilter
public class CustomAuthorize : IAuthorizationFilter
{
private readonly int _input;
public CustomAuthorize(int input)
{
_input = input;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//custom validation rule
if (_input == 1)
{
context.Result = new ForbidResult();
}
}
}
Custom CustomAuthorizeAttribute
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
public CustomAuthorizeAttribute(int input) : base(typeof(CustomAuthorize))
{
Arguments = new object[] { input };
}
}
Use
[CustomAuthorizeAttribute(1)]
public IActionResult About()
I have a simple hosted service(called TransactionService) in a .net core web api app.
I'm having issues with populating a List in the TransactionService
In my TransactionController I'm using the following method to add a transaction:
public IActionResult CreateTransaction(Transaction transaction)
{
// validate
var _transactionS= (TransactionService)_transactionService.Service;
_transactionS.Add(transaction);
return Ok();
}
And in my TransactionService class:
private List<Transaction> transactions = new List<Transaction>();
public void AddTransaction(Transaction transaction)
{
transactions.Add(transaction);
}
protected override Task FilterTransactions()
{
foreach(var item in transactions)
{
//Do some work
}
return Task.CompletedTask;
}
}
So when I call CreateTransaction in my controller this will call the AddTransaction method in my service class.
The FilterTransaction method gets executed every 5 seconds, go through every element of my list and check some conditions, only problem is that my transactions list is empty.
If I add a breakpoint in my AddTransactionMethod it will show me the correct count, but a breakpoint on my foreach statement will show count 0.
This is the Startup class code to register the service
services.AddHostedService<TransactionService>();
services.AddSingleton<IHostedServiceAccessor<ITransactionService>, HostedServiceAccessor<ITransactionService>>();
And the TransactionService setup:
public interface IHostedServiceAccessor<out T> where T : IHostedService
{
T Service { get; }
}
public class HostedServiceAccessor<T> : IHostedServiceAccessor<T> where T : IHostedService
{
public HostedServiceAccessor(IEnumerable<IHostedService> hostedServices)
{
Service = hostedServices.OfType<T>().FirstOrDefault();
}
public T Service { get; }
}
public interface ITransactionService: IHostedService
{
}
internal class TransactionService : TransactionServiceBase, ITransactionService
{
private List<Transaction> transactions = new List<Transaction>();
public TransactionService()
:base(TimeSpan.FromMilliseconds(5000))
{
}
public void AddTransaction(Transaction transaction)
{
transactions.Add(transaction);
}
protected override Task FilterTransactions()
{
foreach (var item in transactions)
{
//Do some work
}
return Task.CompletedTask;
}
}
The TransactionServiceBase class is inheriting form BackgroundService and is a DLL. It has an abstract FilterTransaction method and another one sealed ExecuteAsync()
This question already has answers here:
Dependency Injection wcf
(2 answers)
Closed 6 years ago.
In developing a WPF application that allows editing of article and carrier (pallet, racking) data (in a CRUD-fashion) I'm looking how to manage the lifecycle of the WCF clients connecting to the service that contains the actual data.
I prefer to use an MVVM approach using Caliburn Micro and StructureMap or Castle Windsor.
My main issue is not the creation of WCF client channels or factories, but more important the cleanup after use. I intend to use per-request lifecycle on the server side, as such I will need to create and dispose my clients on a per-request basis. As such I have the following in mind:
public class Article
{
public int Id { get; set; }
public string ArticleId { get; set; }
}
[ServiceContract]
public interface IArticleCrud
{
[OperationContract]
Article CreateArticle(string articleId);
[OperationContract]
void Delete(int articleId);
}
public class ArticlesViewModel
{
private readonly Func<IArticleCrud> articleCrudFactory;
public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory)
{
this.articleCrudFactory = articleCrudFactory;
}
public void Delete(int articleId)
{
// Doesn't work since IArticleCrud is not IDisposable
using (var crud = articleCrudFactory())
{
crud.Delete(articleId);
}
}
}
As noted in the comment this won't work because IArticleCrud is not IDisposable. IArticleCrud is used to create a ChannelFactory on the client side to generate proxies for the service implementing the same interface. I'd happily swap out this code for the following:
public class DeleteArticleCommand : IRequest
{
public int Id { get; set; }
}
public class ArticlesViewModel
{
private readonly IMediator mediator;
public ArticlesViewModel(IMediator mediator)
{
this.mediator = mediator;
}
public void Delete(int articleId)
{
mediator.Send(new DeleteArticleCommand {Id = articleId});
}
}
public class DeleteArticleCommandHandler : RequestHandler<DeleteArticleCommand>
{
private readonly IArticleCrud articleCrud;
public DeleteArticleCommandHandler(IArticleCrud articleCrud)
{
this.articleCrud = articleCrud;
}
protected override void HandleCore(DeleteArticleCommand message)
{
articleCrud.Delete(message.Id);
}
}
However, this doesn't solve my problem as I'm still not dealing with the disposal of the WCF client. I could however make the IMediator create a new nested container on the Send action and have it disposed after the Send action completes, but it seems like a lot of hassle.
Am I getting it all wrong, or does it just require a lot of effort just to perform a WCF call from a WPF application?
As a sidenote, I will be having more services than just these few CRUD services, so the perhaps pragmatic solution of fixing this in my CRUD services is not an option.
I've dealt with the same Problem (WCF-Service used in a WPF Application) and wanted to use the ServiceInterface instead the ServiceClient (which is IDisposable and can be used in a using-block).
One of the solutions to Close the Connection is to cast the Interface to the Client-type and call the .Close()-Method:
public class Article
{
public int Id { get; set; }
public string ArticleId { get; set; }
}
public interface IArticleCrud
{
Article CreateArticle(string articleId);
void Delete(int articleId);
}
public class ArticlesViewModel
{
private readonly Func<IArticleCrud> articleCrudFactory;
public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory)
{
this.articleCrudFactory = articleCrudFactory;
}
public void Delete(int articleId)
{
//Using-Block doesn't work since IArticleCrud is not IDisposable
var crud = articleCrudFactory();
crud.Delete(articleId);
if (crud is ArticleCrud)
(crud as ArticleCrud).Close();
}
}
You can also create a static method in your articleCrudFactory that will Close your IArticleCrud:
public static void CloseInterface(IArticleCrud crud)
{
if (crud is ArticleCrud)
(crud as ArticleCrud).Close();
else { ... }
}
I've done it already with WCF and MVVM and its really easy (if I get your problem right):
public interface IRequest
{
}
public interface IRequestHandler<in TCommand> where TCommand : IRequest
{
void HandleCore(TCommand command);
}
public class DeleteArticleCommand : IRequest
{
public int Id { get; set; }
}
public class ArticlesViewModel
{
private readonly IRequestHandler<DeleteArticleCommand> _handler;
public ArticlesViewModel(IRequestHandler<DeleteArticleCommand> handler)
{
_handler = handler;
}
public void Delete(int articleId)
{
_handler.HandleCore(new DeleteArticleCommand { Id = articleId });
}
}
//On client side
public sealed class WcfServiceCommandHandlerProxy<TCommand>
: IRequestHandler<TCommand> where TCommand : IRequest
{
public void HandleCore(TCommand command)
{
using (var service = new ActuaclWcfServiceClient())
{
service.Send(command); //Or however you are working with you WCF client
}
}
}
//Somewhere on server side
public class DeleteArticleCommandHandler : IRequestHandler<DeleteArticleCommand>
{
private readonly IArticleCrud _articleCrud;
public DeleteArticleCommandHandler(IArticleCrud articleCrud)
{
_articleCrud = articleCrud;
}
public void HandleCore(DeleteArticleCommand message)
{
articleCrud.Delete(message.Id);
}
}
Just register your IRequestHandler interface to be implemented with WcfServiceCommandHandlerProxy type and that's it:
//May vary :)
Register(typeof (ICommandHandler<>), typeof (WcfServiceCommandHandlerProxy<>))
This seems like an obvious question, but is CreateDatabaseIfNotExists.InitializeDatabase atomic?
Currently I have code similar to below. This an attempt to make sure that either database creation completes fully, or the database doesn't exist.
public class MyContext : CreateDatabaseIfNotExists<MyContext>
{
public override void InitializeDatabase(MyContext context)
{
base.InitializeDatabase(context);
//Removed custom initialization code
}
protected override void Seed(MyContext context)
{
//Removed adding / updating seed data
context.SaveChanges();
base.Seed(context);
}
}
public static class DbCreator
{
public static void CreateDatabase()
{
using (MyContext dbContext = new MyContext())
{
try
{
var dbIntializer = new MyDbInitializer();
dbIntializer.InitializeDatabase(dbContext);
}
catch (Exception ex)
{
dbContext.Database.Delete();
throw;
}
}
}
}
I've looked in some obvious places for an answer such as https://msdn.microsoft.com/en-us/library/gg696403(v=vs.113).aspx.
I am using Entity Framework 6.1.3