I have a problem with NHibernate ISession. When I try to persist something wrong into Database (e.g saving an entity with duplicate key on XYZ col) and rolling back Transaction; ISession instance goes to a BROKEN/INVALID state which doesn't persist any record after that, and each time NHibernat throws another exception that tells me about first time issue.
I've used ISession methods like Flush, Clear, Close but my problem exists. Another approach is to request another ISession instance from ISessionFactory but when I use this, another strange problem: illegal attempt to associate a collection with two open sessions.
How to recover an ISession instance without re-requesting another from ISessionFactory?
Thanks in advance :)
You cannot recover the ISession. From documentation:
If the ISession throws an exception you should immediately rollback
the transaction, call ISession.Close() and discard the ISession
instance. Certain methods of ISession will not leave the session in a
consistent state.
Also creating ISession is cheap so there is no reason to try to reuse it. You probably want to have ISession per request if you have MVC application.
You can't, and you shouldn't.
If a transaction fails, you must abort the request and show an error.
The logical corollary is that session exceptions should not be part of your regular flow.
Now, since you're using MVC, here's an example of how error handling might work if you allow errors:
public ActionResult CreateFoo(FooModel model)
{
if (ModelState.IsValid)
{
try
{
SaveThe(model);
TheTransaction.Commit();
return RedirectToAction("Whatever");
}
catch (WhateverTheDuplicateKeyExceptionIs)
{
ModelState.AddModelError("", "Duplicate XYZ");
}
}
return View();
}
Related
I'm trying to create a mostly simple web app with Asp.Net MVC and Entity Framework. I actually finished few projects with it but wasn't satisfied about the code so I'm following some more popular ways to do it. Here is my structure:
Controller gets the request,
I have services which contain business logic. They also use my Database Context to change the data on the database. I didn't want to create another database layer so I'm using them,
I inject my services to controller (with Unity) and call stuff like CustomerService.Delete(Id)
My service deletes the data based on Id.
So my controller does not include any logic or database operations, my services does include both. I think it's a good way to do stuff but I have a problem.
Let's say I add a customer for the first time and there is another table keeping their balance and I want to include a bonus $10 for first registration, when I call my CustomerService.Add(Customer), that method also calls CustomerService.AddBalance(Customer, 10). In those methods I call DbContext.SaveChanges, here is the problem, I call SaveChanges 2 times, and if CustomerService.AddBalance(Customer, 10) fails for some reason I will still have the customer data but not the balance one. I know I can use a transactions but where do I put that code? If I knew there was a place which runs last before request is finished, I could call SaveChanges() there and it would work but I think that's not a great idea either.
Basically I want to call SaveChanges() once per request but I couldn't find a good place to do it.
Thanks
If you are doing any work with the database you want to be using transactions. If you don't you are going to leave your db in an inconsistent state if one of your calls fails. Using transactions, nothing will be committed in the database until you call Commit. You can call SaveChanges as much a you like and it won't make a difference.
You can create a TransactionScope in a attribute and then add it to any controller action where you are accessing the db. Here' one I use
[AttributeUsage(AttributeTargets.Method)]
public class TransactionAttribute : ActionFilterAttribute
{
private TransactionScope TransactionScope { get; set; }
public override void OnActionExecuting(HttpActionContext filterContext)
{
TransactionScope =
new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted
});
}
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
if (TransactionScope == null)
return;
if (filterContext.Exception == null)
{
TransactionScope.Complete();
return;
}
TransactionScope.Dispose();
}
}
You could put the transaction code in BeginRequest stash it in HttpContext and commit on EndRequest. This is going to create a TransactionScope for every call that asp.net handles.
According to documentation EF by default sets all the changes to database in transaction until SaveChanges() is called.
So you can extract the logic of adding to database to separate methods, create separate method which saves changes to DB and design your code as following:
AddCustomer to DB (do not call save changes)
AddBalance to DB(do not call save changes)
SaveChanges on the end of the in your service method
This will guarantee that all happens in transaction and in case of any error changes to database won't be applied.
I have found that creating an Extension to your Context (i am assuming your are using EF) is a good way to go:
public static class TIContextCompleteExtention
{
public static void Complete(this TIContext context)
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
throw ex;
}
}
public static async Task CompleteAsync(this TIContext context)
{
try
{
await context.SaveChangesAsync();
}
catch (Exception ex)
{
throw ex;
}
}
}
The Above TIConext is derived from EF's dbContext.
Wherever you need to COMPLETE your transaction use
_context.Complete(); or _context.CompleteAsync() instead of EF's SaveChanges() / SaveChangesAsync()
If you later swap out your ORM all you need to do is change the above extensions to fit your new Context.
Hope this helps.
I got an API with a controller and a service, when invoking one of the action in the controller I must apply a validation, this validation need to check the data in DB to validate that is correct.
As far as I can see there are two ways of handling this
1- Validate before calling the "update" to prevent the error
public IActionResult UpdateCustomer(CustomerDto customer)
{
if (!customerService.Validate(customer))
{
return Send400BadRequest();
}
customerService.Update(customer);
return Send200Ok();
}
2- Call the update validate inside and throw an Exception.
public IActionResult UpdateCustomer(CustomerDto customer)
{
customerService.Update(customer);
return Send200Ok();
}
In customer service
public void Update(CustomerDto customer)
{
if (!Validate(customer)
throws new CustomValidationException("Customer is not valid");
//Apply update
}
We already have an ActionFilter to handle the CustomValidationException so it will return a BadRequest.
1)
Pros
+Don't use Exception to use the running flow
Cons
-Controller is more fat, has more decision on each case it will decide which is the output
2)
Pros
+Operation is more atomic, all logic is inside the service.
+Easier to test
+Every use of the method will be validated.
Cons
-Use exception to manage the flow.
Which is a better solution?
I really need arguments to defend one or the other.
If you have a Business Logic Layer and a Service Layer, I prefer to keep all Business Logic Rules including Business Logic Validations in Business Logic Layer and use Service Layer as a wrapper around Business Logic Layer and throw Exception in Business methods.
When deciding about whether to use Exception for Business Validation rules or not, you can consider:
1) It's better that your Business methods be a Unit of Work. They should perform a complete task. So it's better they contain also validation rules. This way you can reuse such Business Logic Layer across different Service Layers or use the same Unit of Work in different methods of the same Service Layer. If you throw a Business Validation Exception in Business Logic Layer, you will not face with risk of forgetting validation or using another validation rule by mistake and each service method / action will perform a single task for you and will be as lightweight as possible.
Think about when you may need to expose a WCF service for some clients or for example if you may use ASP.NET MVC without using WebAPI or iff you want to use the same logic in another Action method in the same WebAPI.
If you put Business Logic validations in Web API controller, when creating WCF service methods or creating MVC Actions or other service methods, you may forget to apply validations or may apply wrong validations with different rules in the new Service Layer.
2) Considering the first benefit, can you return a meaningful value from methods that shows success, failure, or contain suitable information about failure reason in output?
I believe it's not suitable to use out put of method for all these goals. The method output is method output, it should be data in such business application. It should not be sometimes a status, sometimes data or some times message. Throwing exception will solve this problem.
I am going against the other opinions on here and saying that the first method both clearly illustrates what the intent of your method is and if you ever decide to not return a 400 error, its a bit easier to pull that off in scenario #1.
Additionally, some thoughts on exceptions. Exceptions should be exceptional, meaning unexpected events that occur in your code. A company not passing a validation check is not an exception-al event, it either does pass or does not pass. Passing a User object into the ValidateCompany() method should throw an exception.
Here is a good answer on the similar topic of exception throwing. It uses an easy example problem to determine when in that case an exception should be thrown or not.
In regards to "Easier to test" - I don't see how. Your controller will have two tests with any option you choose, a valid company and an invalid company. Your service will have two tests with any option you choose, a valid company and an invalid company (obviously simplifying your service layer a bit here). In any case you want to ensure both your controller action and your service layer can handle an invalid and valid company object.
I would prefer 2 :)
Because I think service might be called from another node not only the asp.net controller so it would be nice for me if all validation logic is handled in the single layer like Service layer.
i think handling exception by using httpresponse message is much better then any one else. Atleast you got the proper error response with proper http response message as output.
public HttpResponseMessage TestException()
{
try
{
//if your code works well
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, ex.ToString());
}
}
I would do it this way:
public IActionResult UpdateCustomer(CustomerDto customer)
{
try
{
consumerService.Update (customer);
}
catch (CustomValidationException)
{
return Send400BadRequest ();
}
return Send200Ok ();
}
And in your CustomerService:
public void Update(CustomerDto customer)
{
if (!Validate(customer))
throw new CustomValidationException("Customer is not valid");
}
This way your service has the validation logic. So any other callers to your service will also have their inputs validated before attempting an update and hence will get proper error messages.
Your controller will not have any validation code. And moreover, having the try-catch block means you can gracefully handle any other errors the Update call might throw. Hope that helps.
Receive a validatable customer model, pass this model to the data service layer, and perform exception
handling in the controller if the data service layer fails.
Customer model
Implement IValidatableObject to trap business logic related errors.
public class CustomerModel : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// example validation
if ( Balance < 100 )
yield return new ValidationResult("Balance >= 100 req.", new [] { nameof(Balance) });
}
public string Name { get; set; }
public double Balance { get; set; }
}
API Controller
Receive a CustomerModel in your public facing UpdateCustomer API method, then reference ModelState to determine if the customer is valid.
public IActionResult UpdateCustomer(CustomerModel customer)
{
if(ModelState.IsValid) // model validation succeeded
{
try
{
customerService.Update(customer);
}
catch (ServiceUpdateException svcEx)
{
// handled failure at the service layer
return Conflict();
}
catch (Exception ex)
{
// unhandled error occured
return InternalServerError(ex);
}
// update succeeded
return Ok();
}
// invalid model state
return BadRequest();
}
Service (Data Layer)
public void Update(Customer customer)
{
//Apply update
try
{
database.Update(customer);
}
catch (DataStorageException dbEx)
{
throw new ServiceUpdateException(dbEx);
}
catch
{
throw;//unknown exception
}
}
I think that you should validate in both the controller and the service, but validate slightly different things. Especially if what starts off as just an api turns into an api, with a mvc site and a wpf admin interface as often happens.
Using Validation Attributes and Model Binding gives the data a quick "once over" check. Did they supply the id for the customer to update? Did they submit foreign key value for a related entity? Is the price between 0 and 1,000,000? If you have a website then you also get client validation out of the box. Crucially there no need to connect to the database at all, as the data is "obviously" wrong.
Validation in the service is also required as you may end up with 3 or 4 applications calling this service, and you want to write the business logic once. Some validation eg. referencing foreign keys can only be done in the database, but there is nothing wrong in throwing an exception. Consumers of your api should have access to the range of valid values, users of the website should be choosing from a drop down etc, so this circumstance should be exceptional
I got a generic repository - should the repository be able to throw exceptions or should I keep it dumb? If I chose to throw exceptions from it, should the service layer then catch it and throw an exception with a more friendly message before it goes to the Controller?
Pos1: Repository (Throw) => Service(Catch, Throw new) => Controller(Catch)
Pos2: Repository => Service(Throw) => Controller(Catch)
Definitely Option 1.
I would also replace the term "dumb" with "separation of concerns" in your thinking. There is no reason for a Repository to be dumb. It has a job to do and that will involve exceptions.
It will also involve throwing them for two reasons:
To package a real error that has happened for the consuming code.
To throw an exception under given conditions that violate what you want this class to do. These conditions might not involve an exception thrown by the framework and can be solely related to the "intelligence" you want your Repository to have.
The Repository has to involve encapsulating ALL of this intelligence, leaving the calling code to simply need to know how to deal with a limited set of exceptions. Otherwise, your calling code needs to deal with, for example, the full panoply of LINQ exceptions, coupling it to a technology that should be the exclusive domain of the Repository.
So part of the Repositiory's intelligence has to be throwing a well known, but limited set of exceptions related to its specific purpose.
The same reasoning applies to the Service Layer, if you have one. It needs to deal with exceptions in exactly the same way: encapsulating the "intelligence" that is specific to its task. And again, the same happens with the controller. It should interpret the exceptions it receives from the Service Layer (if there is one) according to its own purposes and concerns.
So separation of concerns, but never dumb. Not even Mute: each layer needs to squeal when it has to.
Should the repository be able to throw
exceptions or should I keep it dumb?
Yes - the repository should be able to throw exceptions. Keeping something 'dumb' doesn't mean it's not comletely self-aware :)
The caveat that 'exceptions should be exceptional' still applies - you might find this "Creating More Exceptional Exceptions" article of interest and it's also of relevance to your question.
If I chose to throw exceptions from
it, should the service layer then
catch it and throw an exception with a
more friendly message before it goes
to the Controller?
Generally, I've not re-thrown exceptions although there's merit in doing that. A pragmatic half-way-house would be to do that for exception types which you want to handle gracefully for some reason.
If you're using something like the Ms Ent Libs Application Logging Block you can set a policy (via config) that allows you to control what happens when exceptions occur - re-throwing them or otherwise; so that would be a useful approach to stop hard-coding yourself into a specific result.
Also this might be of interest: Are exceptions really for exceptional errors?
Generally speaking, you should simply return null from your repository if your query returns no data. You can then test for the null in the repository, if you wish, before sending the data to your view.
public ActionResult Details(int id) {
Dinner dinner = dinnerRepository.FindDinner(id);
if (dinner == null)
return View("NotFound");
else
return View("Details", dinner);
}
http://nerddinnerbook.s3.amazonaws.com/Part4.htm
For edits I would let your Data Access Layer or your repository throw an exception, and catch it in the controller, like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
// Success!
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
// Old-school data validation from ASP.NET MVC 1.0
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
// Return original view, so user can correct errors.
return View(dinner);
}
}
http://nerddinnerbook.s3.amazonaws.com/Part5.htm
I have a edited RESTful wizard based upon Shoulders of Giants | A RESTful Wizard Using ASP.Net MVC… Perhaps? . This wizard has a CANCEL button which, when pressed, fires the code below.
// If the user cancels, drop out altogether
if (!string.IsNullOrEmpty(CANCEL_BUTTON)) {
Session.Remove(VACANCYWIZARD_SESSION_KEY);
repository._entities.ObjectStateManager.GetObjectStateEntry(inProgressVacancyWizard.Vacancy).Delete();
return this.RedirectToAction("Index", "Home");
}
Now, to be able to call SaveChanges() after the cancel button I have to manually delete the entry from the wizard from my ObjectStateManager. But when you cancel the wizard by just manually returning to the home page it stays in and a next call to _entities.SaveChanges() will throw an exception that it cannot Save the object, from the wizard progress to the database, since it is still in the object state.
Note that in between the steps of the wizard I do not save anything to the database. I keep it in session state retrieving it each step:
NewVacancy inProgressVacancyWizard = Session[VACANCYWIZARD_SESSION_KEY] as NewVacancy;
Somehow, however, the inProgressVacancyWizard.Vacancy does appear in the ObjectStateManager so I have to delete it else I will get errors about incomplete Vacancies models while the _entities.SaveChanges() is called for another object.
Is there a way to cover for this problem?
//edit
After some reading I have found out that the fundaments of my repository are not good. As found here. Currently I'm doubting to implement the option mentioned in "One ObjectContext instance per business transaction" in the same article. Would that be a wise thing? I would like to hear some more about it since it will be a major refactor.
public static Repository Instance
{
get
{
if (instance == null) {
instance = new Repository();
}
return instance;
}
}
#region Constructor: Repository()
/// <summary>
/// Constructor
/// </summary>
private Repository()
{
_entities = new DBModelEntitiesNew2();
}
It seems like you are using a single ObjectContext instance across multiple requests. Don't do that. It will cause you nothing but misery. It makes your web server stateful. Dispose the ObjectContext after the response is rendered (we do it, indirectly, from Controller.Dispose), and new up a new one for the next request.
I have a website where I allow users to create new Part records. I'm trying to figure out the best way to validate specific fields for uniqueness. I want to make sure that somebody doesn't try to add a Part with PartNumber 1234 if that PartNumber already exists on a different Part.
The Web Application is using Asp.net MVC with fluent nHibernate for mapping my objects to the database. I'm using Castle validation on my view models for things like ValidateNonEmpty, ValidateRange, etc. Should I use the ValidateSelf method to query the repository to see if that part number already exists? Something doesn't feel right about using my Repository on the ViewModel.
Would it be better for me to place that logic on the controller action? That doesn't seem right because I expect my ViewModel to already be Validated at the point (during ModelBind).
Or maybe its none of the above. Thanks for any help on this one.
UPDATE
Ok, not sure if this will help, but here is what my Save action looks like for a typical Create Action in my project:
public ActionResult Create(PartViewModel viewModel)
{
//I think I'd like to know if its Valid by this point, not on _repository.Save
if(ModelState.IsValid)
{
try
{
var part = _partCreateViewModelMap.MapToEntity(viewModel);
_repository.Save(part);
return Redirect("~/Part/Details/" + part.Id);
}
catch (Exception e)
{
// skip on down...
}
}
// return view to edit
return View(viewModel);
}
I have been asked this question many times. My friends were worried about whether they can perform data access from the validator code. The answer is simple. If you need to do this, you should do it. Usually we need to do such checks at each level of abstraction. And after all checks you should be ready to catch an exception, caused by unique constraint violation.
If you define a unique constraint within the database, then why not delegate the responsibility to check for whether a unique value already exists to the database? Using NHibernate, you can use the NHibernate.Exceptions.ISQLExceptionConverter interface to capture and transform known errors relating to constraint violations. You can also use NHibernate.Exceptions.IViolatedConstraintNameExtracter implementers (see NHibernate.Exceptions.TemplatedViolatedConstraintNameExtracter) to get at the grubby details of your database exception, and transform it into a user-friendly message, repackage as a validation exception of your chosing and catch it in the relevant controller.
Example of a quick, very specific quick and dirty exception converter from one of my projects:
Imports NHibernate
Imports NHibernate.Exceptions
Imports System.Data.SqlClient
Imports System.Data.Common
Namespace NHibernate
Public Class ConstraintViolationExceptionConverter
Implements ISQLExceptionConverter
Public Function Convert(ByVal adoExceptionContextInfo As Global.NHibernate.Exceptions.AdoExceptionContextInfo) As System.Exception Implements Global.NHibernate.Exceptions.ISQLExceptionConverter.Convert
Dim dbEx As DbException = ADOExceptionHelper.ExtractDbException(adoExceptionContextInfo.SqlException)
If TypeOf dbEx Is SqlException Then
Dim sqlError As SqlException = DirectCast(dbEx, SqlException)
Select Case sqlError.Number
Case 547
Return New ConstraintViolationException(adoExceptionContextInfo.Message, adoExceptionContextInfo.SqlException)
End Select
End If
Return SQLStateConverter.HandledNonSpecificException(adoExceptionContextInfo.SqlException, adoExceptionContextInfo.Message, adoExceptionContextInfo.Sql)
End Function
End Class
End Namespace
Configured through the web.config/nhibernate-configuration/session-factory property element:
<property name="sql_exception_converter">csl.NHibernate.ConstraintViolationExceptionConverter, csl</property>
Edit: Should probably mention that the converter interface has changed in recent versions of NHibernate, the interface from this example is from NHibernate.dll v2.1.0.4000
I typically put a Service layer between my controllers and repositories.
The service layer would then handle the validation and calls to the repository.
Then, if there's a validation error in the service layer, I throw a custom exception, catch it in the controller, and inject the errors in to the model state.
I have no answer for your question but you can check sharparchitecture.net site. It contains some best practives for asp.net mvc and nhibernate. Also I can recommend you to check xval project and tutorials about Validating with Data Annotation Validators
I have found the solution that works for me is to
1.) Ask if the entity is valid to execute your validation work.
2.) After this is complete you should have something on your object to show it's valid or not (in my case I use a CSLA like concept of "broken rules").
3.) If you have something like this you can verify the object is valid before NHibernate tries to persist it as shown below.
The only issue with this approach is that you do need to implement an interface on each entity requiring validation. If you can live with this it will stop NHibernate from persisting the changes of an object that's not valid according to your rules.
using System;
using NHibernate;
using NHibernate.Event;
using Validation.Entities.Interfaces;
using Persistence.SessionBuilder;
namespace Persistence.Validation
{
public class ValidationEventListener : IPreInsertEventListener, IPreUpdateEventListener
{
public bool OnPreInsert(NHibernate.Event.PreInsertEvent #event)
{
var entityToInsert = #event.Entity as IBusinessBase;
if (entityToInsert != null)
{
if (entityToInsert.BrokenRules != null)
{
RollbackTransactionBecauseTheEntityHasBrokenRules();
}
}
return false;
}
public bool OnPreUpdate(NHibernate.Event.PreUpdateEvent #event)
{
var entityToUpdate = #event.Entity as IBusinessBase;
if (entityToUpdate != null)
{
if (entityToUpdate.BrokenRules != null)
{
RollbackTransactionBecauseTheEntityHasBrokenRules();
}
}
return false;
}
private void RollbackTransactionBecauseTheEntityHasBrokenRules()
{
try
{
ISession session = SessionBuilderFactory.GetBuilder().CurrentSession;
if (session != null)
{
session.Transaction.Rollback();
}
}
catch (Exception ex)
{
//this will force a rollback if we don't have a session bound to the current context
throw new NotImplementedException();
}
}
}
}
I would say this matters on your architecture. With MVC apps that I have done in the past we abstract away the domain stuff away from the web stuff and naturally we use dependency injection to avoid hard dependencies.
When it comes to validating the model when you are in the act of binding it, yes you could easily use the service, repository, or whatever you have next in your architecture in a ValidateSelf method. I think the question rises of what about that dependency.
If I remember correctly you can create your own custom binder that will use your dependency injection framework to plug-in any services your model needs for validation when you create it, call MVC's default binder to fill in the object, then call into Castle Validation's framework to do the validation. This isn't a fully thought solution, but hopefully it provokes some ideas.