XML Repository; to Save() or not to Save() - c#

What would be a better approach for an xml-based repository:
1) Save changes to the underlying xml document on each call to the repository...
public class XmlRepository1
{
private XDocument xDocument;
public void CrudOp()
{
// Perform CRUD operation...
// Call Save()
xDocument.Save(path);
}
}
or
2) Provide the end-user with a SaveChanges() method...
public class XmlRepository2
{
private XDocument xDocument;
public void CrudOp()
{
// Perform CRUD operation...
// DON'T call save
}
// Provide a SaveChanges() method to the end-user...
public void SaveChanges()
{
xDocument.Save(path);
}
}
My inclination leans towards option 1, because providing a SaveChanges() method doesn't really seem like a repositories responsibility. However, I'm second-guessing this decision for a couple of reasons:
a) In a multi-threaded environment, this gives the end-user an easy way to roll-back changes should a call to the repository fail, leaving objects in a partially-mutated state.
b) Option 2 provides a "batch-like" paradigm, which I can see as being more flexible for a variety of reasons.

Consider adding some sort of transaction support (close to your second apporach).
public class XmlRepository2
{
public void CrudOp()
{
// DON'T call save
}
public MakeTransacedChanges(Action<XmlRepository2> makeChanges)
{
try{
makeChanges(this);
saveChanges();
}
catch (RepositoryException e)
{
//revert changes
}
}
private void saveChanges()
{
xDocument.Save(path);
}
}

I prefer to have separate Save method in repository to have a chance to revert my changes if something will go wrong.
I found this article Repositories and the Save Method. Hope it will help.

Related

Saving data to multiple tables with dependency injection and maintaining transection in asp.net core app

I have simple classes to saves and get data (not like repository pattern). But while saving data to multiple tables I want to maintain a transaction. So I just went through Unit of work pattern, but that will require me to do a lot of changes. So I'm thinking if my approach will do the same as UOF.
Here's my code:
CalalogueRepository:
public interface ICalalogueRepository
{
void Create(string guid, string fileName);
}
public class CalalogueRepository : ICalalogueRepository
{
private CatalogueContext _catalogueContext;
public CalalogueRepository(CatalogueContext catalogueContext)
{
_catalogueContext = catalogueContext;
}
public void Create(string guid, string fileName)
{
_catalogueContext.Catalogues.Add(new Catalogue
{
CatalogueId = guid,
FileName = fileName
});
}
}
StuffRepo:
public interface IStuffRepo
{
void Create(string guid, List<StuffModel> myStuff);
}
public class StuffRepo : IStuffRepo
{
private CatalogueContext _catalogueContext;
public StuffRepo(CatalogueContext catalogueContext)
{
_catalogueContext = catalogueContext;
}
public void Create(string guid, List<StuffModel> myStuff)
{
//add stuff to _catalogueContext.StuffTable.Add
}
}
Finally a class that does the SaveChanges and Commit:
public class UOW : IUOW
{
private CatalogueContext _catalogueContext;
private ICalalogueRepository _calalogueRepo;
private IStuffRepo _stuffRepo;
public UOW(CatalogueContext catalogueContext,
ICalalogueRepository calalogueRepo,
IStuffRepo stuffRepo)
{
_catalogueContext = catalogueContext;
_calalogueRepo = calalogueRepo;
_stuffRepo = stuffRepo;
}
public void Save (string guid, string fileName, List<StuffModel> myStuff)
{
using (IDbContextTransaction transection = _catalogueContext.Database.BeginTransaction())
{
_calalogueRepo.Create(guid, fileName);
_stuffRepo.Create (guid, myStuff);
_catalogueContext.SaveChanges();
transection.Commit();
}
}
}
I think there is only 1 CatalogueContext throughout the call.
Ok, so as you can see here, AddDbContext is the right way to register it as you wrote in the comment on the question.
Here it says that AddDbContext will register the context as scoped.
And here you can find what scoped means.
Overall I think you are right that your code will use the same context throughout the Save method.
Couple thoughts:
Probably you want to have a try-catch in case an exception is thrown and you want to rollback
If you are not sure if it's working why not try it? You should test your code/application anyways.
Probably this could be done in a better way, but I don't have the context about the rest of your code/application, so I cannot tell. (Not sure what you mean by "...Unit of work pattern, but that will require me to do a lot of changes." for example.)
Now the Create methods not self-contained, meaning if you just want to add a new item to the table it is not enough to call Create, but separately call SaveChanges(). This is not an explicit problem, but has to be kept in mind and might be a little bit confusing for new developers on the project.

Transaction management in dependent services

I am interested in the architectural solution of the following moment.
I have:
public class GenericRepository<T> : IDisposable {
public GenericRepository(ISession session){
_session = session;
};
public T InsertAsync(T entity){...};
public IQueryable<T> Read(){...};
public T UpateAsync(T entity){...};
public void DeleteAsync(T entity){...};
public Task Commit(){
return _session.Transaction.Commit();
};
public void Dispose(){
if(_session.Transaction.IsActive){
_session.Transaction.Rollback();
}
};
}
public class UserService{
public UserService(GenericRepository<User> repository){...}
public long CreateUser(string userName){
...
_repository.Commit(); // [1]
};
}
public class OrganizationService{
public OrganizationService(GenericRepository<Organization> repository){...}
public int CreateOrganization(string code){
...
_repository.Commit(); // [2]
};
}
The following registration is used:
services.AddScoped<ISession>(x => x.GetRequiredService<NHSessionProvider>().OpenSession());
services.AddScoped(typeof(GenericRepository<>));
services.AddScoped<UserService>();
services.AddScoped<OrganizationService>();
These CreateOrganization and CreateUser can be used independently in any parts of the code:
public IActionResult Post([FromServices] OrganizationService service, [FromBody] string code){
service.CreateOrganization(code);
return Ok();
}
public IActionResult Post([FromServices] UserService service, [FromBody] string userName){
service.CreateUser(userName);
return Ok();
}
However, now I have a new service:
public class MyBillingService{
public MyBillingService(GenericRepository<Contractor> repository, OrganizationService organizationService, UserService userService){...}
public int CreateNewContractor(string organizationCode, string userName){
...
_organizationService.CreateOrganization(organizationCode);
...
_userService.CreateUser(userName);// [3]
...
_repository.Commit(); // [4]
}
}
In this implementation, CreateOrganization and CreateUser have their own transactions, and if [3] throws an exception, then the organization will be created anyway.
Ok, because ISession is registered as Scoped, then I can delete _repository.Commit from CreateOrganization and CreateUser([1] and [2]). In this case, [4] will be responsible for committing all changes.
But what then to do when OrganizationService and UserService are used independently? After all, now they have become non-independent services and cannot save data without delegating the commit of changes to some other service:
public IActionResult Post([FromServices] UserService service, [FromServices] TransactionService transaction, [FromBody] string userName){
service.CreateUser(userName);
transaction.Commit();
return Ok();
}
As far as this decision is a good one?
Transactions requires a unit of work. There is no other way to coordinate repositories. The reason you're facing issues here is that your entire design is wrong.
First and foremost, you should not have these repositories at all. You're using EF Core, which is an ORM, and already implements the repository and unit of work patterns. Using an ORM is opting to use a third-party library for your DAL. Wrapping your own DAL layer around that is pointless and imposes needless maintenance and testing costs on your application with zero benefit. Your services should depend on your context directly.
Then, services should be self-contained units of functionality. If they depend on other services, you're doing it wrong. The service should correspond with a particular subdomain of your application. If users and organization need to be managed together transactionally, then you should have one service that encompasses both.
Alternatively, if you want/need to keep the two separate, then you would need to incorporate the concept of sagas.
So I've started to move more towards what Chris mentioned in his answer and use the ISession directly, but I have used a generic repository in the past. Your repos can't correctly handle transactions that are already started.
So my generic repo has a couple of methods
protected virtual TResult Transact<TResult>(Func<TResult> func)
{
if (_session.Transaction.IsActive)
return func.Invoke();
TResult result;
using (var tx = _session.BeginTransaction(IsolationLevel.ReadCommitted))
{
result = func.Invoke();
tx.Commit();
}
return result;
}
protected virtual void Transact(System.Action action)
{
Transact(() =>
{
action.Invoke();
return false;
});
}
Then the methods that are implementing the repo functionality look like this
public bool Remove(T item)
{
Transact(() => _session.Delete(item));
return true;
}
This allows the method to use an existing Transaction if it is already started, otherwise create your transaction for this work.
You also should not have a Dispose in your repo since you don't own the reference to ISession. It's life cycle should be handled by whoever created that instance.
The generic repository also shouldn't have commit functionality except when it is explicitly starting a new transaction. So now you need to have something that handles starting and committing said transaction. In a web scenario you are typically in a session per request scenario. This would mean you are creating your session in BeginRequest and disposing of it in EndRequest. I then use a transaction attribute to manage creating transactions prior to executing the controller action and commit/rollback after the execution of the controller method.

How to create an aspect decorator to handle EF transactions

I'm working (maintaining) on a dll assembly that acts as a Data Access Layer, there are many methods that requires transaction handling, many other do not, it's a currently "functional" dll, without any transaction handling method, I need to add it, so I'm looking for an easy way to add a transaction handler.
I'm wondering if is it possible to use AOP to create a decorator that I can add to the methods that requires a transaction.
I would like to have something like this:
[Transaction]
void MyDbMethod()
{
//DoSomething
myContext.SaveChanges();
}
For the EF model definition I'm using Code First, the current project uses Unity framework for some other DI tasks, can that framework be used for this?
If someone faces this same issue, I did not found any "by hand" solution, instead I used the PostSharp library and its OnMethodBoundaryAspect class, but be careful, at this moment the free/express license has limitations about the amount of classes where you can use it, so read carefully its limitations.
using System.Transactions;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace MyProject
{
[PSerializable]
public class Transaction : OnMethodBoundaryAspect
{
public Transaction()
{
//Required if the decorated method is async
ApplyToStateMachine = true;
}
public override void OnEntry(MethodExecutionArgs args)
{
//TransactionScopeAsyncFlowOption.Enabled => Required if the decorated method is async
var transactionScope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled);
args.MethodExecutionTag = transactionScope;
}
public override void OnSuccess(MethodExecutionArgs args)
{
var transactionScope = (TransactionScope)args.MethodExecutionTag;
transactionScope.Complete();
}
public override void OnExit(MethodExecutionArgs args)
{
var transactionScope = (TransactionScope)args.MethodExecutionTag;
transactionScope.Dispose();
}
}
}
You can do it using NConcern .NET AOP Framework.
This is an open source runtime AOP framework on which I actively work.
public class DataAccessLayer : IAspect
{
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
//define how to rewrite method
yield return Advice.Basic.Arround(invoke =>
{
using (var transaction = new TransactionScope(...))
{
invoke(); //invoke original code
transaction.Complete();
}
});
}
}
Your business
public class MyBusiness
{
[Transaction]
void MyDbMethod()
{
}
}
Attach transaction scope aspect to you business
Aspect.Weave<DataAccessLayer>(method => method.IsDefined(typeof(TransactionAttribute), true);

Generic repository factory and service composition

In previous question folks helped me to solve repository lifetime problem, now there's a question how to make it work nicely in composite service.
let's say i have services:
public class OrderService : IOrderService
{
IRepository<Order> orderRepository;
public OrderService(IRepositoryFactory repositoryFactory)
{
orderRepository = repositoryFactory.GetRepository<Order>();
}
public void CreateOrder(OrderData orderData)
{
...
orderRepository.SubmitChanges();
}
}
public class ReservationService : IReservationService
{
IRepository<Reservation> reservationRepository;
public ReservationService(IRepositoryFactory repositoryFactory)
{
reservationRepository = repositoryFactory.GetRepository<Reservation>();
}
public void MakeReservations(OrderData orderData)
{
...
reservationService.SubmitChanges();
}
}
And now the intersting part - composition service:
public class CompositionService : ICompositionService {
IOrderService orderService;
IReservationService reservationService;
public CompositionService(IOrderService orderService, IReservationService reservationService)
{
this.orderService = orderService;
this.reservationService = reservationService;
}
public void CreateOrderAndMakeReservations(OrderData orderData)
{
using (var ts = new TransactionScope())
{
orderService.CreateOrder(orderData);
reservationService.MakeReservations(orderData);
ts.Complete();
}
}
}
Problem is, that it won't work correctly if IRepositoryFactory lifestyle is transient (because you would get two different datacontexts and that would require distributed transactions to be enabled, which we try to avoid). Any ides how to write this correctly?
My observations:
In general, factories should be singletons. If your factory isn't a singleton, then you are probably just hiding another factory behind it.
Factories are meant for creating objects on demand. Your code simply creates a repository in the constructor, so I don't really see the difference between that and simply making the repository a direct injection parameter in the constructor.
These all seem to me like a workarounds around a more fundamental problem (described in your first question) and these workarounds only make the problem more complicated. Unless you solve the root problem you will end up with a complex dependency schema and a smelly code.
IMO - this is a Distributed Transaction scenario.
In the example you mentioned, OrderService & ReservationService use the same data context is an implementation detail hidden in the code.
I don't think it is correct to pass this knowledge up to the CompositionService by wrapping the service calls in a TransactionScope as now the composition service is aware of the shared data context & so needs to use a TransactionScope to run the code correctly.
In my opinion, the composition service code should look like:
try{
if(orderService.TryCreateOrder(orderData)){
if(reservationService.TryMakeReservation(orderData)){
reservationService.Commit();
orderService.Commit();
}
else{
orderService.TryRollbackOrder(orderData);
throw new ReservationCouldNotBeMadeException();
}
}
else{
throw new OrderCouldNotBeCreatedException();
}
}
catch(CouldNotRollbackOrderServiceException){
// do something here...
}
catch(CouldNotCommitServiceException){
// do something here...
}
In this case, the OrderService.TryCreateOrder method will insert an Order with a PendingReservation status or some other relevant status which indicates that the Order is inserted, but not completed. This state will change on the commits are called on the services (UnitOfWork pattern?)
In this case, the implementation details of the services are completely hidden from the consumer of the service, while composition is also possible, independent on the underlying implementation detail.
HTH.

Checking Role-based permissions on all actions in centralized or clean way in .Net applications

I am trying to avoid the conventional:
if(!user.HasPermission(Actions.UpdateRecord))
{
// code to update record
}
on a large number of permissions all over my application.
I am looking for a means of checking for permissions in an effective and (if possible) elegant manner.
In this case there are multiple actions within each permission.
How about putting a decorator on your dataaccess objects. The decorator pattern is very useful for doing things like handling permissions. Your dataAccess layer can do just data access and then your decorate those classes with something that handles permissions and permissions only.
It is very elegant...
http://en.wikipedia.org/wiki/Decorator_pattern
There are a lot of ways to do this. The important thing is that you want to encapsulate the concern of checking permissions. One way to do this is with a strategy pattern. Encapsulate the action in a class, and get the class via a factory method. The factory can do the security check, and return a different strategy for disallowed actions.
For example:
public abstract class SecureAction
{
public void PerformAction();
}
public class UpdateRecords : SecureAction
{
public void PerformAction()
{
//code to do the update
}
}
public class DoesNotHavePermissionAction : SecureAction
{
public void PerformAction()
{
//code to handle missing permissions
}
}
public class SecureActionFactory
{
public void GetUpdateRecordsAction(User user)
{
if(user.HasPermissions(Actions.UpdateRecord)) {return new UpdateRecordsAction();}
return new DoesNotHavePermissionAction();
}
}

Categories