nHibernate, ASP.NET MVC, s#arp architecture and multiple identical databases - asp.net-mvc

We are currently developing an application based on NHibernate and ASP.NET MVC and a SQL Server backend. Since I'm fairly new to NHibernate, I'm tryig to understand best practices.
Our application requires every user to have it's own SQL Server database. These databases all have an identical structure.
Our customers are identified with a customercode, e.g. 1500.
We've come up with a custom connection provider for nHibernate, which we already use in our nServiceBus backend services:
public class DynamicConnectionProvider : DriverConnectionProvider
{
public override IDbConnection GetConnection()
{
IDbConnection conn = Driver.CreateConnection();
try
{
var messageExecutionContext = ServiceLocator.Current.GetInstance<ITTTContextProvider>().CurrentContext;
if (messageExecutionContext.CustomerId == 0)
{
conn.ConnectionString = ConfigurationManager.ConnectionStrings["dev"]
.ConnectionString;
}
else
{
conn.ConnectionString = ConfigurationManager.ConnectionStrings["default"]
.ConnectionString
.FormatWith(messageExecutionContext.CustomerId);
}
conn.Open();
}
catch (Exception)
{
conn.Dispose();
throw;
}
return conn;
}
}
This connection provider checks the customer code in a context object and sets the connectionstring accordingly.
We are planning to provide a HttpContext aware ITTTContextProvider. For this I have two questions:
How can we retrieve the customer code from the url and put it into our context object for every request? when we use the following route?
<main-site-url>/{customercode}/{controller}/{action}/{id}
Is this method of connecting to several identical databases valid or is it better practice to construct a sessionfactory foreach customer database?

In order to get the customercode you need to access the route data, something along the lines of
HttpContextBase currentContext = new HttpContextWrapper(HttpContext.Current); //ServiceLocator.Current.GetInstance<ITTTContextProvider>().CurrentContext;
RouteData routeData = RouteTable.Routes.GetRouteData(currentContext);
var cusomterCode = routeData.Values["customercode"]
My second suggestion would be not to put this code in the above snippet provided. Abstract it away. See Joshua's answer which highlights the approach I am thinking of.
Can't really help on the second question, actually not familiar with both frameworks mentioned.

See my recent blog post which shows how to use a subdomain to connect to different databases, although it would be easy to implement your own version of ITenantContext that grabbed the customer code from the request url. Also uses separate session factories for each tenant.
http://www.yellowfeather.co.uk/2011/01/multi-tenancy-on-sharp-architecture/

Related

Save new entity in changeRequestInterceptor method

Im just thinkin to save some audit details of all changes on entities to database.so im have come up with that "changeRequestInterceptor" which looks like where i can implement my audit logic in.
Well,the question is simply is it possible to add this newly created entity to request payload ?
var adapter = breeze.config.getAdapterInstance('dataService');
adapter.changeRequestInterceptor = function (saveContext, saveBundle) {
this.getRequest = function (request, entity, index) {
var em = saveContext.entityManager;
var en = em.createEntity('DbLog',
{
userId: //userId
logDate: new Date(),
log: //some log text
});
//How to add "en" entity to requet payload.
return request;
};
this.done = function (requests) {
};
};
I'm firmly with Jay in favor of creating audit records on the server, not the client. The client could care less and shouldn't bear the burden of creating the extra material nor have to burn bandwidth for that kind of stuff. It's really not a client concern.
There is a save interceptor in the Breeze-oriented server components. There is NO save interceptor in the Breeze client save pipeline.
We have such a thing in our DevForce product. After careful thought we did not bring it over to Breeze and we're confident that we were wise to leave it out. Interceptors add complexity and obscurity. Some times they are necessary (as with our server-side interceptors) but we don't think they are helpful or necessary for a client-side save operation ... for reasons I'm about to explain.
Breeze never calls EntityManager.saveChanges on its own. You do that. Which means you are in perfect position to decide what happens before Breeze does its thing. That includes creating supplementary entity changes just before save if that's what you need.
In our samples, we encapsulate the EntityManager in some kind of a service component (e.g., a "DataContext" or a "DataService"). Application layers (e.g., viewmodels) can't talk to an EntityManager directly; they have to go through the DataContext to perform persistence operation.
Your DataContext API should expose a "save" method (or methods) that wraps the EntityManager.saveChanges call with the appropriate business logic.
Follow this pattern and you'll find ample opportunities to implement pre- and post-save behaviors.
Of course Breeze does offer save interception at lower levels of the stack. The DataServiceAdapter, for example, handles the details of translating between Breeze entity representation and whatever your particular backend service requires in the way of HTTP setup and JSON objects. You want these details abstracted for you when writing your DataContext.
You might need some interception way down here ... and you'll find the requisite hooks. But now we're talking about what you can do below the Breeze entity abstraction. This feels like the wrong place to be adding/modifying/deleting entities even if it is technically possible to do so.
Another alternative is to perform the Add on the server instead of the client.
[HttpPost]
public SaveResult SaveWithFoo(JObject saveBundle) {
ContextProvider.BeforeSaveEntitiesDelegate = AddNewFoo;
return ContextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> AddNewFoo(Dictionary<Type, List<EntityInfo>> saveMap)
var foo = new Foo();
// update the entity with any custom data. For example:
foo.OrderDate = DateTime.Today;
var ei = ContextProvider.CreateEntityInfo(foo);
List<EntityInfo> fooInfos;
if (!saveMap.TryGetValue(typeof(Foo), out fooInfos)) {
fooInfos = new List<EntityInfo>();
saveMap.Add(typeof(Foo), fooInfos);
}
fooInfos.Add(ei);
return saveMap;
}

How to only allow access from WCF Data Service ServiceOperation

I use WCF with my ASP.NET MVC app, my data service get data from my (EF 4.1) .mdf file. But there is some feild that I want to show with authentication, for example:
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Exercies", EntitySetRights.All);
config.SetServiceOperationAccessRule("GetAllExercies", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
[WebGet]
public IQueryable<Exercise> GetAllExercies(string name, string pass)
{
if (Membership.ValidateUser(name, pass))
return CurrentDataSource.Exercies;
else
return CurrentDataSource.Exercies.Where(e => e.Public == true);
}
Now when user access httx://localhost/MyService.svc/Exercies, they can get everything although they are not given the username and pass.
My temporary solution is re name GetAllExercies to just Exercies but I not sure is there any better way...
Yes, there is a better solution: query interceptors. In fact using the same name for entity set and service operation tends to lead to problems in certain scenarios (the $metadata is "confusing" for the clients). It's also not 100% secure (doesn't prevent accessing the entity through some navigation property if you have that).
See this http://msdn.microsoft.com/en-us/library/dd744842.aspx. The idea is that you make the auth filter part of the entity set query, and WCF DS Service makes sure that it will be used everywhere that entity set is accessed.

ASP.NET MVC: Updating model from within model?

In a controller, I do the following:
DBContext DB = new DBContext();
var u = DB.Users.Find(1);
u.firstname = "blah";
UpdateModel(u);
DB.SaveChanges();
I want to do the same from within a model...
namespace Project.Models
{
public class User
{
public void resetPassword()
{
// Generate new password, etc.
this.password = "blah";
}
}
}
Any idea how I go about doing this? It seems UpdateModel() is only available from within controllers.
I'm using EntityFramework Code-First CTP5.
I think UpTheCreek is correct but it probably needs some explanation so I'll try to expand on his/her answer. The first step would be to use the repository pattern. You can find many examples of this pattern in MVC with a google search - this is a particularly gentle introduction (about 3/4's down the page).
The walkthrough goes on to mention dependency injection, and that's something that's also worth looking in to. I tend to favor Ninject myself, however there are other dependency injection containers available.
Putting data access concerns in your model is not a good idea.
Update: Yes, you'd usually have a data access layer for this. As Andy says, the currently fashionable way to do this is using a repository. As a rule, you don't want anything in your model that is not core business logic.

Using MVC and fluent Nhibernate, how do I validate unique fields on my ViewModel before I bind them to my Domain Object and Save them?

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.

Asp.Net Core Identity - Using a stored procedure to save new users

I see a lot of information on ASP.Net Core Identity and have been piecing together how to customize it, since I am building a site for use against an existing SQL Server database.
I have been able to customize my replacement for the AspNetUsers table, and have new users saving properly. Since in the existing systems that use this database there are a couple of stored procedure calls that happen that wrap a lot of functionality, I would like to use the same approach. So I think that instead of the default call like this:
var result = await _userManager.CreateAsync(user, model.Password);
I would need something that can call one or more stored procedures to create the user. Should I inherit from UserManager and override the CreateAsync call? If so, can I use my existing user store? I'm a little fuzzy on what this looks like, WRT identity. Thanks!
You should keep using _userManager.CreateAsync, but configure it in such a way that your own implementation of a UserStore is used.
In Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services
.AddIdentity<MyUser>()
.AddUserStore<MyUserStore>();
}
Then, create a custom UserStore, where you can call your context class (including calls to stored procedures):
public class MyUserStore : IUserStore<MyUser>
{
private MyContext _db;
public MyUserStore(MyContext db)
{
_db = db;
}
public async Task<IdentityResult> CreateAsync(MyUser user, CancellationToken cancellationToken)
{
// simply store entity in DB
user = _db.Users.Add(user).Entity;
await _db.SaveChangesAsync();
// or run stored procedure
await _db.Database.ExecuteSqlCommandAsync("usp_MyUserCreationStoredProcedure #p0, #p1", user.FirstName, user.LastName);
return IdentityResult.Success;
}
}
You can check the relevant documentation on how to create custom user stores for more information.
I would consider keeping Identity functions calls as is and adding application specific calls separately. CreateAsync does quite a lot of good things like password hashing, time stamping and user name/email normalization. This functionality is the actual valuable part of Identity product, and rewriting it would only introduce security vulnerabilities and will require substantial time otherwise used for application development. Identity is not just SQL tables, but also all the logic managing authentication workflows with implemented security best practices.

Resources