When the Service layer is only executing a task (checking if Id exists, sending an email, etc.), what is the best way for it to let the controller know if there were any errors?
Two solutions I can think of:
Always passing in an extra "broken rules" parameter by reference to the methods in the Service layer which it would update if there were any error.
Have the Service raise an exception and having the controller do a try/catch.
Are either one of these two approaches recommended? If not, what approach could I take to have the Service layer let the controller know what something went wrong (such as invalid parameter)?
Your service should collection all the broken rules and after that throw the "BrokenRuleException". Your controller will catch the "BrokenRuleException" and then use the brokenrules to update the user interface.
I created interface:
public interface IModelStateWrapper
{
void AddModelError(string name, string error);
}
Then I created implementation for every controller:
public class ControllerModelStateWrapper : IModelStateWrapper
{
private ModelStateDictionary _dictionary;
public ControllerModelStateWrapper(ModelStateDictionary dictionary)
{
_dictionary = dictionary;
}
public void AddModelError(string name, string error)
{
if (_dictionary[name] == null)
_dictionary.Add(name, new ModelState());
_dictionary[name].Errors.Add(error);
}
}
Every service implements:
public interface IModelWrapperService
{
IModelStateWrapper ModelWrapper {get;set;}
}
And then I set it in Controller:
public UserController(IUserService service)
{
_service.ModelWrapper = new ControllerModelStateWrapper(ModelState);
}
IModelStateWrapper is not the best name, because this interface can work not only with Controller.ModelState. Works pretty ok. You can easily replace IModelStateWrapper with mock or other implementation in your service tests. This solution also automatically sets ModelState as invalid.
I think that throwing the BrokenRuleException is a good choice.
Personally, I don't like to put state in a service, it's often a singleton (performed by a DI container), and only has other singletons collaborators (in my case, domain objects).
Related
So I'm not sure if I'm just missing something, but basically every example of DI I see with asp.net core shows passing of parameters from the appSettings.json file through a constructor in the controller and then to anything else.
Can I bypass the Controller and just inject directly a Class Library?
For an example of what I'm trying to do, let's say I have appSettings.json with
"EmailSettings":{"smtpServer":"mail.example.com", "port":123, "sendErrorsTo":"errors#example.com"}
Then a Class Library for EmailServices
EmailSettings.cs
public class EmailSettings{
public string smtpServer {get;set;}
public int port {get;set;}
public string sendErrorsTo {get;set;}
}
IEmailService.cs
public interface IEmailService
{
void SendErrorEmail(string method, Exception ex);
}
and EmailService.cs
public class EmailService :IEmailService
{
private readonly EmailSettings _emailSettings;
public EmailService(EmailSettings emailSettings)
{
_emailSettings = emailSettings;
}
public void SendErrorEmail(string method, Exception ex)
{
....
}
}
Startup.cs in the main asp.net core application
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddScoped<IEmailService, EmailService>(p => {
return new EmailService(p.GetService<EmailSettings>());
});
...
}
Without loading the EmailServices or the appsetting.json parameters through the controller and then into the BusinessLayer class library, I want to be able to call the SendErrorEmail from BusinessLayer (or any other place).
DoWork.cs
public MakeItWork()
{
try
{...}
catch (exception ex)
{
IEmailService.SendErrorEmail("BAL - MakeItWork",ex)
}
}
But it just fails with a null exception. The DI in the startup doesn't create the EmailService in place of the IEmailService, and I'm going to guess the parameters are not there either.
Thanks for any help you can give.
----EDIT----
I ended up just switching to using AutoFac for DI. It's able to accomplish what I was looking for. Accepted the answer below to give Phantom the points for trying to assist.
A couple of things:
In your MakeItWork() method, you have code that "calls" a method using the interface name - not even sure how that will compile. You need to use an object of a class that implements that interface to actually make method calls at runtime. For example, in your DoWork class, you could have a constructor requesting for an instance of a class that implements the IEmailService interface and store it for future use in other methods.
Second, in the Services collection, you are adding a "Scoped" dependency (in the ConfigureServices method). A "scoped" dependency is only created upon a (http)Request, typically via calls to controllers. From your code and your explanation, it looks like you are wanting to add a Singleton object for your IEmailService interface. So, instead of adding a Scoped dependency use AddSingleton - as you have done, you can also create the specific object in the call to AddSingleton - that means this object will be provided every time you request it (through class constructors, for example). If you are using it as a singleton, you should also make sure that it is thread safe. Alternatively, you can also add the dependency using AddTransient - if you use this, a new object will be created every time you request it.
Update:
Sample Code
Modify your ConfigureServices to make the EmailService as Transient (this means a new object every time this service is requested):
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddTransient<IEmailService, EmailService>();
...
}
Your "DoWork" class should request the EMail Service in the constructor:
public class DoWork()
{
private IEmailService _emailService;
//Dependency should be injected here
public DoWork(IEmailService emailService)
{
_emailService = emailService;
}
public MakeItWork()
{
try
{...}
catch (exception ex)
{
//Use the saved email service object to do your work
_emailService.SendErrorEmail("BAL - MakeItWork", ex)
}
}
}
It doesn't end here. The question remains as to how you are going to create an Object of the DoWork class. For this, one idea is to create an interface for the DoWork class itself and then setup the container for that interface as well. Then wherever you would want to use the DoWork implementation you can "request" the interface for DoWork. Or use the container directly to create an instance.
The definition of my interface is as follows:
public interface IApplicationSettings
{
string LoggerName { get; }
string NumberOfResultsPerPage { get; }
string EmailAddress { get; }
string Credential { get; }
}
The implementation of this interface is given below:
public class WebConfigApplicationSettings : IApplicationSettings
{
public string LoggerName
{
get { return ConfigurationManager.AppSettings["LoggerName"]; }
}
public string NumberOfResultsPerPage
{
get { return ConfigurationManager.AppSettings["NumberOfResultsPerPage"]; }
}
public string EmailAddress
{
get { return ConfigurationManager.AppSettings["EmailAddress"]; }
}
public string Credential
{
get { return ConfigurationManager.AppSettings["Credential"]; }
}
}
I also created a factory class to obtain the instance of the concrete implementation of WebConfigSettings as follows:
public class ApplicationSettingsFactory
{
private static IApplicationSettings _applicationSettings;
public static void InitializeApplicationSettingsFactory(
IApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
public static IApplicationSettings GetApplicationSettings()
{
return _applicationSettings;
}
}
Then I resolved dependency as follows:
public class DefaultRegistry : Registry {
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
}
}
Now when i running my application it throw me following exception:
Exception has been thrown by the target of an invocation.
and the Inner Exception is
No default Instance is registered and cannot be automatically determined for type 'Shoppingcart.Infrastructure.Configuration.IApplicationSettings'\r\n\r\nThere is no configuration specified for Shoppingcart.Infrastructure.Configuration.IApplicationSettings\r\n\r\n1.) Container.GetInstance(Shoppingcart.Infrastructure.Configuration.IApplicationSettings)\r\n
I am using StructureMap for MVC5
The reason your code isn't working is because when you call ObjectFactory.GetInstance<IApplicationSettings>(), your registry hasn't been registered and thus, StructureMap's configuration is incomplete.
I believe what you're trying to do is the following (tested and works):
public class ApplicationSettingsFactory
{
public ApplicationSettingsFactory(WebConfigApplicationSettings applicationSettings)
{
_applicationSettings = applicationSettings;
}
private static IApplicationSettings _applicationSettings;
public IApplicationSettings GetApplicationSettings()
{
return _applicationSettings;
}
}
With your registry configured like this:
public DefaultRegistry() {
Scan(scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
this.For<IApplicationSettings>().Use(ctx => ctx.GetInstance<ApplicationSettingsFactory>().GetApplicationSettings());
}
I can't really tell you why your registration fails in StructureMap, but if you allow me, I would like to feedback on your design.
Your design and code violates a few basic principles:
You are violating the Interface Segregation Princple (ISP).
The ISP describes that interfaces should be narrow (role interfaces) and should not contain more members than a consumer uses. You however defined an application wide IApplicationSettings interface and your intention is to inject into any consumer that needs some configuration settings. Changes are really slim however that there is a consumer that actually needs all settings. This forces the consumer to depend on all members, it makes the API more complex, while it just needs one.
You are violating the Open/Closed Principle (OCP).
The OCP describes that it should be possible to add new features without making changes to existing classes in the code base. You will however find yourself updating the IApplicationSettings interface and its implementations (you will probably have a fake/mock implementation as well) every time a new setting is added.
Configuration values aren't read at startup, which makes it harder to verify the application's configuration.
When a consumer makes a call to a property of your IApplicationSettings abstraction, you are forwarding the call to the ConfigurationManager.AppSettings. This means that if the value isn't available or incorrectly formatted, the application will fail at runtime. Since some of your configuration values will only be used in certain cases, this forces you to test every such case after you deployed the application to find out whether the system is configured correctly.
Solution
The solution to these problems is actually quite simple:
Load configuration values at start-up.
Inject configuration values directly into a component that needs that exact value.
Loading the configuration values directly at start-up, allows the application to fail fast in case of a configuration error, and prevents the configuration from being read over and over again needlessly.
Injecting configuration values directly into a component, prevents that component from having to depend on an ever-changing interface. It makes it really clear what a component is depending upon, and bakes this information in during application start-up.
This doesn't mean though that you can't use some sort of ApplicationSettings DTO. Such DTO is exactly what I use in my applications. This basically looks as follows:
public static Container Bootstrap() {
return Bootstrap(new ApplicationSettings
{
LoggerName = ConfigurationManager.AppSettings["LoggerName"],
NumberOfResultsPerPage = int.Parse(
ConfigurationManager.AppSettings["NumberOfResultsPerPage"]),
EmailAddress = new MailAddres(
ConfigurationManager.AppSettings["EmailAddress"]),
Credential = ConfigurationManager.AppSettings["Credential"],
});
}
public static Container Bootstrap(ApplicationSettings settings) {
var container = new Container();
container.RegisterSingle<ILogger>(
new SmtpLogger(settings.LoggerName, settings.EmailAddress));
container.RegisterSingle<IPagingProvider>(
new PagingProvider(settings.NumberOfResultsPerPage));
// Etc
return container;
}
In the code above you'll see that the creation of the ApplicationSettings DTO is split from the configuration of the container. This way I can test my DI configuration inside an integration test, where the start-up projects configuration file is not available.
Also note that I supply the configuration values directly to the constructors of components that require it.
You might be skeptic, because it might seem to pollute your DI configuration, because you have dozens of objects that require to be set with the same configuration value. For instance, your application might have dozens of repositories and each repository needs a connection string.
But my experience is that is you have many components that need the same configuration value; you are missing an abstraction. But don't create an IConnectionStringSettings class, because that would recreate the same problem again and in this case you aren't really making an abstraction. Instead, abstract the behavior that uses this configuration value! In the case of the connection string, create an IConnectionFactory or IDbContextFactory abstraction that allows creation of SqlConnection's or DbContext classes. This completely hides the fact that there is a connection string from any consumer, and allows them to call connectionFactory.CreateConnection() instead of having to fiddle around with the connection and the connection string.
My experience is that makes the application code much cleaner, and improves the verifiability of the application.
Thanks every one for responses. I found my solution. The solution is instead of using Default Registry I created another class for resolve the dependencies. Inside the class I used
ObjectFactory.Initialize(x =>
{
x.AddRegistry<ControllerRegistry>();
});
instead of
IContainer Initialize() {
return new Container(c => c.AddRegistry<ControllerRegistry>());
}
Then inside ControllerRegistry I resolved dependencies as follows:
// Application Settings
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
Then I called that class inside Global.asax as follows:
Bootstrap.ConfigureDependencies();
Finally inside Global.asax I resolved dependency for Factory class as follows:
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
My entire code is given below:
Bootstrap class (newly created)
public class Bootstrap
{
public static void ConfigureDependencies()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry<ControllerRegistry>();
});
}
public class ControllerRegistry : Registry
{
public ControllerRegistry()
{
// Application Settings
For<IApplicationSettings>().Use<WebConfigApplicationSettings>();
}
}
}
Global.asax
Bootstrap.ConfigureDependencies();
ApplicationSettingsFactory.InitializeApplicationSettingsFactory
(ObjectFactory.GetInstance<IApplicationSettings>());
I am designing a web application and a windows service and want to use the unit of work + repository layer in conjunction with a service layer, and I am having some trouble putting it all together so that the client apps control the transaction of data with the unit of work.
The unit of work has a collection of all repositories enrolled in the transaction along with commit and rollback operations
public interface IUnitOfWork : IDisposable
{
IRepository<T> Repository<T>() where T : class;
void Commit();
void Rollback();
}
The generic repository has operations that will be performed on the data layer for a particular model (table)
public interface IRepository<T> where T : class
{
IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, IList<Expression<Func<T, object>>> includedProperties = null, IList<ISortCriteria<T>> sortCriterias = null);
PaginatedList<T> GetPaged(Expression<Func<T, bool>> filter = null, IList<Expression<Func<T, object>>> includedProperties = null, PagingOptions<T> pagingOptions = null);
T Find(Expression<Func<T, bool>> filter, IList<Expression<Func<T, object>>> includedProperties = null);
void Add(T t);
void Remove(T t);
void Remove(Expression<Func<T, bool>> filter);
}
The concrete implementation of the unit of work uses entity framework under the hood (DbContext) to save the changes to the database, and a new instance of the DbContext class is created per unit of work
public class UnitOfWork : IUnitOfWork
{
private IDictionary<Type, object> _repositories;
private DataContext _dbContext;
private bool _disposed;
public UnitOfWork()
{
_repositories = new Dictionary<Type, object>();
_dbContext = new DataContext();
_disposed = false;
}
The repositories in the unit of work are created upon access if they don't exist in the current unit of work instance. The repository takes the DbContext as a constructor parameter so it can effectively work in the current unit of work
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _dbContext;
private readonly DbSet<T> _dbSet;
#region Ctor
public Repository(DataContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
#endregion
I also have a service classes that encapsulate business workflow logic and take their dependencies in the constructor.
public class PortfolioRequestService : IPortfolioRequestService
{
private IUnitOfWork _unitOfWork;
private IPortfolioRequestFileParser _fileParser;
private IConfigurationService _configurationService;
private IDocumentStorageService _documentStorageService;
#region Private Constants
private const string PORTFOLIO_REQUEST_VALID_FILE_TYPES = "PortfolioRequestValidFileTypes";
#endregion
#region Ctors
public PortfolioRequestService(IUnitOfWork unitOfWork, IPortfolioRequestFileParser fileParser, IConfigurationService configurationService, IDocumentStorageService documentStorageService)
{
if (unitOfWork == null)
{
throw new ArgumentNullException("unitOfWork");
}
if (fileParser == null)
{
throw new ArgumentNullException("fileParser");
}
if (configurationService == null)
{
throw new ArgumentNullException("configurationService");
}
if (documentStorageService == null)
{
throw new ArgumentNullException("configurationService");
}
_unitOfWork = unitOfWork;
_fileParser = fileParser;
_configurationService = configurationService;
_documentStorageService = documentStorageService;
}
#endregion
The web application is an ASP.NET MVC app, the controller gets its dependencies injected
in the constructor as well. In this case the unit of work and service class are injected. The action performs an operation exposed by the service, such as creating a record in the repository and saving a file to a file server using a DocumentStorageService, and then the unit of work is committed in the controller action.
public class PortfolioRequestCollectionController : BaseController
{
IUnitOfWork _unitOfWork;
IPortfolioRequestService _portfolioRequestService;
IUserService _userService;
#region Ctors
public PortfolioRequestCollectionController(IUnitOfWork unitOfWork, IPortfolioRequestService portfolioRequestService, IUserService userService)
{
_unitOfWork = unitOfWork;
_portfolioRequestService = portfolioRequestService;
_userService = userService;
}
#endregion
[HttpPost]
[ValidateAntiForgeryToken]
[HasPermissionAttribute(PermissionId.ManagePortfolioRequest)]
public ActionResult Create(CreateViewModel viewModel)
{
if (ModelState.IsValid)
{
// validate file exists
if (viewModel.File != null && viewModel.File.ContentLength > 0)
{
// TODO: ggomez - also add to CreatePortfolioRequestCollection method
// see if file upload input control can be restricted to excel and csv
// add additional info below control
if (_portfolioRequestService.ValidatePortfolioRequestFileType(viewModel.File.FileName))
{
try
{
// create new PortfolioRequestCollection instance
_portfolioRequestService.CreatePortfolioRequestCollection(viewModel.File.FileName, viewModel.File.InputStream, viewModel.ReasonId, PortfolioRequestCollectionSourceId.InternalWebsiteUpload, viewModel.ReviewAllRequestsBeforeRelease, _userService.GetUserName());
_unitOfWork.Commit();
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
return View(viewModel);
}
return RedirectToAction("Index", null, null, "The portfolio construction request was successfully submitted!", null);
}
else
{
ModelState.AddModelError("File", "Only Excel and CSV formats are allowed");
}
}
else
{
ModelState.AddModelError("File", "A file with portfolio construction requests is required");
}
}
IEnumerable<PortfolioRequestCollectionReason> portfolioRequestCollectionReasons = _unitOfWork.Repository<PortfolioRequestCollectionReason>().Get();
viewModel.Init(portfolioRequestCollectionReasons);
return View(viewModel);
}
On the web application I am using Unity DI container to inject the same instance of the unit of work per http request to all callers, so the controller class gets a new instance and then the service class that uses the unit of work gets the same instance as the controller. This way the service adds some records to the repository which is enrolled in a unit of work and can be committed by the client code in the controller.
One question regarding the code and architecture described above. How can I get rid of the unit of work dependency at the service classes? Ideally I don't want the service class to have an instance of the unit of work because I don't want the service to commit the transaction, I just would like the service to have a reference to the repository it needs to work with, and let the controller (client code) commit the operation when it see fits.
On to the windows service application, I would like to be able to get a set of records with a single unit of work, say all records in pending status. Then I would like to loop through all those records and query the database to get each one individually and then check the status for each one during each loop because the status might have changed from the time I queried all to the time I want to operate on a single one. The problem I have right now is that my current architecture doesn't allow me to have multiple unit of works for the same instance of the service.
public class ProcessPortfolioRequestsJob : JobBase
{
IPortfolioRequestService _portfolioRequestService;
public ProcessPortfolioRequestsJob(IPortfolioRequestService portfolioRequestService)
{
_portfolioRequestService = portfolioRequestService;
}
The Job class above takes a service in the constructor as a dependency and again is resolved by Unity. The service instance that gets resolved and injected depends on a unit of work. I would like to perform two get operations on the service class but because I am operating under the same instance of unit of work, I can't achieve that.
For all of you gurus out there, do you have any suggestions on how I can re-architect my application, unit of work + repository + service classes to achieve the goals above?
I intended to use the unit of work + repository patterns to enable testability on my service classes, but I am open to other design patterns that will make my code maintainable and testable at the same time while keeping separation of concerns.
Update 1
Adding the DataContext class that inheris from EF's DbContext where I declared my EF DbSets and configurations.
public class DataContext : DbContext
{
public DataContext()
: base("name=ArchSample")
{
Database.SetInitializer<DataContext>(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
base.Configuration.ProxyCreationEnabled = false;
}
public DbSet<PortfolioRequestCollection> PortfolioRequestCollections { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new PortfolioRequestCollectionConfiguration());
base.OnModelCreating(modelBuilder);
}
}
If your purpose for using Unit of Work (UoW) was for testability, you took the wrong path. Unit of work does nothing for testability. Its main purposes is to provide atomic transactions to disparate data sources, provide UoW functionality to a data layer that doesn't already provide it, or to wrap an existing UoW in a way that makes it more easily replaceable... something which you've nullified by using the generic repository (this tightly couples it to Entity Framework anyways).
I suggest you get rid of the Unit of Work completely. Entity Framework is already a UoW. Even Microsoft has changed their mind and no longer recommend UoW with EF.
So, if you get rid of UoW, then you can just use repositories to wrap your EF queries. I don't suggest using a generic repository, as this leaks your data layer implementation all over your code (something your UoW was already doing), but rather create Concrete repoTsitories (these can use generic repositories internally if you like, but the generic repository should not leak outside of your repository).
This means your service layer takes the specific concrete repository it needs. For instance, IPortfolioRepository. Then you have a PortfolioRepository class that inherits from IPortfolioRepository which takes your EF DbContext as a parameter that gets injected by your Depndency Injection (DI) framework. If you configure your DI container to instance your EF context on a "PerRequest" basis, then you can pass the same instance to all your repositories. You can have a Commit method on your repository that calls SavesChanges, but it will save changes to all changes, not just to that repository.
As far as Testability goes, you have two choices. You can either mock the concrete repositories, or you can use the built-in mocking capabilities of EF6.
I have been through that hell hole myself and here's what I have done:
Ditch the UoW completely. EF's DBContext is a UoW basically. No point in re-inventing the wheel.
Per MSDN:
DbContext Class
Represents a combination of the Unit-Of-Work and Repository patterns
and enables you to query a database and group together changes that
will then be written back to the store as a unit.
Service layer + Repo layer seemed like a good choice. However, repos are always a leaky abstraction and espcially when DBContext's DbSet are the equivalent of repositories.
Then when the need for a Windows service arises, things become muddied further with another layer now. Throw async or background processing in the mix, and things quickly start leaking.
If you ask my 2 cents, I would say go with the service layer + EF, one wrapping business logic, the other one wrapping UOW/Repository pattern.
Alternatively, and for Windows Services especially, I'm finding that moving to a command-query based approach works better.
Not only it helps testability, it also helps in asynchronous tasks where I don't have to worry about keeping the DBContext alive even after the request has ended (DBContext is now tied with the command handler and stays alive as long as the async command stays alive).
Now if you've recently ended up digesting all those facts about UOW/Repository pattern, then surely, just even reading about Command-Query pattern will make your mind hurt. I have been down that path but trust me, its worth the time to at least look into it and giving it a try.
These posts may help:
Meanwhile... on the query side of my architecture
Meanwhile... on the command side of my architecture
If you're brave enough (after digesting thru CQRS), then take a look at MediatR which implements the Mediator pattern (which basically wraps up command-query with notifications) and allows to work via pub-sub. The pub-sub model suits nicely in the Windows Service and services layer.
So I have a method in my service, which I will call from a controller:
public void SendMessage(Message message) {
message.Property = "Random";
try {
// try some insert logic
}
catch (Exception) {
// if it fails undo some stuff
// return the errors
throw;
}
// if there are no errors on the return the operation was a success
// but how do I get the Service generated data?
}
Edit:
So the question isn't really about getting my code to work it's a problem I have with the Repository Pattern whilst using a Service Layer as a 'go between' for communication between the DAL and Presentation
So I have a separate assembly called DataLibrary.
The DataLibrary has my models (Message), my repositories and Services (MessageService)
In my MVC site I would typically have a controller, with CRUD functionality. It would look something like this:
public ActionResult Create(Message message) {
if(ModelState.IsValid) {
db.insert(message);
}
Return View(message);
}
But by using the Repository Pattern, with a service layer for communication I have this instead:
public ActionResult Create(MessageCreateModel message) {
if(ModelState.IsValid) {
MessageService.SendMessage(message.ToDTO());
}
Return View(message);
}
How do I know that the operation was successful or unsuccessful and for what reason?
How do I retrieve the populated data from the service's business logic at the same time as the above?
And how do I achieve both of these two above while sticking as close as possible to MVC design pattern / spearation of concerns for extensibility?
First of all, why do you go through as service if it's just delegating the work to your repository? If you have implemented your repository properly (i.e. being a complete abstraction) there is no need to use the service. Simply call the repository directly from your controller. You can read more about the repository pattern in my blog.
But that doesn't really adress the issue.
So how do you handle errors? When it comes to exceptions: Simply do not catch it ;) Exceptions are after all exceptions and is not something that you typically can handle to deliver the expected result.
As we are talking about the data layer that usually means a stable database engine where it's expected that the read/write will succeed. Hence there is no need for any other error handling than using exceptions.
In ASP.NET MVC you can handle transactions with an attribute and use try/catch to fill the model state as shown here:
[HttpPost, Transactional]
public virtual ActionResult Create(CreateModel model)
{
if (!ModelState.IsValid)
return View(model);
try
{
model.Category = model.Category ?? "Allmänt";
var instruction = new Instruction(CurrentUser);
Mapper.Map(model, instruction);
_repository.Save(instruction);
return RedirectToAction("Details", new {id = instruction.Id});
}
catch (Exception err)
{
// Adds an error to prevent commit.
ModelState.AddModelError("", err.Message);
Logger.Error("Failed to save instruction for app " + CurrentApplication, err);
return View(model);
}
}
You really didn't provide enough information about your architecture is structured to answer this question. However, if you want to get a value back from the SendMessage method, adding a return value instead of void is a good place to start.
I think you should first decide how are you going to design your architecture. Are you go with service oriented, if so your service methods have to be return something for inform controllers. So think your service layer like a border of a country, and the other country's borders are controllers. And you have to let trade these two countries. This can be done with return object which contains return data and also service errors and so on.
If you only want to put your some business logic into your service layer then you probably dont need independent layers. Just some loose coupling is enough for you. So you can return basic clr objects or domain objects or application objects. In a very basic example like this:
//AService service method
public AnEntity ServiceMethod(AFilterViewModel aFilter)
{
//do some validation
try
{
//some transactional operations
}
catch
{
//do some log and rollback it...
throw;
}
var anEntity = _aRepository.GetSomeEntity(x=> x.Something == aFilter.Something);
return anEntity;
}
//controller method
public ActionResult GetSomething(AFilterViewModel aFilter)
{
try
{
var entity = _aService.ServiceMethod(aFilter);
AViewModel model = MapToView(entity);
return View(model);
}
catch
{
return RedirectToAction("Error");
}
}
As you see above the controller and service layer methods can share each others objects. They have boundaries to each other and they coupled. But your architecture decides how much they coupled.
You can also do these mappings one way only. Something like service to Controller only or Controller to service only. If you dont want to use your viewmodel in service layer, you should always do mappings in service layer. Otherwise do your object mapping in controllers. And also dont forgot to put your viewmodel's into another library, its very important. These are something like "value objects".
I use Entity Framework 4 and ASP.NET MVC 3. I made a custom membership provider and use Ninject to inject an EFAccountRepository into it (Bound IAccountRepository to EFAccountRepository).
This account repository has an ObjectContext injected into it. I also use this repository (and others) in my controllers. For this reason when I bound IContext to my ObjectContext, I set the scope to "per request" so the ObjectContext only lives in one request and is shared between the repositories.
I am sometimes get the following error when trying to log in:"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
I wonder how often the membership provider gets instantiated. I injected the repository into the membership provider by marking the repository property with [Inject] and calling Kernel.Inject in the Application_Start function in the global.asax file.
If the provider gets instantiated more than once I would have to inject again I suppose. However, I don't get a null pointer exception, so I don't think that's it.
Update 1
Here's some code:
MyNinjectModule.cs
public override void Load()
{
Bind<IMyContext>().To<MyObjectContext>().InRequestScope();
// put bindings here
Bind<IAccountRepository>().To<EFAccountRepository>
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var kernel = new StandardKernel(new MyNinjectModule());
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
kernel.Inject(Membership.Provider);
}
MyMembershipProvider.cs
[Inject]
public IAccountRepository accountRepository { get; set; }
public override bool ValidateUser(string username, string password)
{
// I get the exception here.
return (from a in accountRepository.Accounts
where a.UserName == username
&& a.Password == password
select true).SingleOrDefault();
}
EFAccountRepository.cs
private readonly IMyContext context;
public EFAccountRepository(IMyContext context)
{
this.context = context;
}
public IQueryable<Account> Accounts
{
get { return context.Accounts; }
}
MyObjectContext.cs
public class MyObjectContext : ObjectContext, IMyContext
{
public IObjectSet<Account> Accounts { get; private set; }
public FlorenceObjectContext()
: this("name=DomainModelContainer")
{
}
public FlorenceObjectContext(string connectionString)
: base(connectionString, "DomainModelContainer")
{
Accounts = CreateObjectSet<Account>();
}
}
PS: I'm always open to comments on my code in general ;).
The exception says that you are incorrectly handling disposing of your context. Somewhere you call context.Dispose (or have context in using) but after that you want to use context again which is not possible because context is already disposed. If you are using per request context you must dispose context only once at the end of request processing (when you are sure that no code will use the context).
You didn't specify a scope for your EFAccountRepository binding so it defaults to .InTransientScope(). This means a new instance of the object will be created each time you resolve the IAccountRepository [refer to https://github.com/ninject/ninject/wiki/Object-Scopes ].
Also, transient scope objects
are automatically garbage collected as soon as there are no references to them [Ninject doesn't cache them]
are not automatically disposed by anyone
In contrast, you bound MyObjectContext to IObjectContext .InRequestScope(). This means it will be reused when you are in the same HTTP request handling operation.
Also, a request scope object
won't be garbage collected until your http request is done
might be automatically disposed once the HTTP request is done, if it's IDisposable. [Not sure precisely when, but from other questions I have seen I suspect it depends on the version of Ninject]
Now, ObjectContext is IDisposable, so it seems reasonable to conclude that
an object reference to the IObjectContext exists, and you are using the IObjectContext outside of the HTTP request which it was created in.
Ninject has automatically disposed of it, since the HTTP request has completed.
In order to solve the issue, you need to figure out why your object context object reference is surviving so long, and consider either eliminating the long-livedness... or removing its dependency on short-lived (request-scoped) objects.
[note clearly the question already has an accepted answer, but I think the accepted answer was kind of hard to understand.]