I am trying to write an extension method for the MVC controller class, since I see such code repeatedly in my program:
if (viewModel == null)
{
return HttpNotFound();
}
return View(viewModel);
The idea is that I want an extension method called ViewModelResult() to take care of this, so that it will return either an ActionResult or HttpNotFound result depending on whether the view model is available. This way, I dont have to write these 3-4 lines of code every time.
However, it seems that the protection level of the methods View() and HttpNotFound() in the MVC controller is causing some serious trouble. I've written the code as below but it will not work:
public static class ExtensionController
{
public static ActionResult ViewModelResult(this Controller controller, ViewModel viewModel)
{
if (viewModel == null)
{
return controller.HttpNotFound();
}
return controller.View(viewModel);
}
}
It throws error messages such as "System.Web.MVC.Controller.View() is inaccessible due to its protection level". This confuses me, I thought in extension methods all private and protected methods of the very object labeled by this keyword are accessible, just like when you write a method in this class. But I've been proved wrong, those non-public methods are inaccessible in extension methods.
Now the question is, how can I get by this issue? I am kinda clueless, don't know what I can do about this. The MVC controller class comes within the .NET framework, and I cannot modify the source code. It is not recommended to change internal implementation of .NET framework anyway. Can anyone help? What do you recommend me to do in this case?
You can create a subclass of the Controller class and add methods to that.
public abstract class ControllerBase : Controller
{
protected ActionResult ViewModelResult(ViewModel viewModel)
{
if (viewModel == null)
{
return HttpNotFound();
}
return View(viewModel);
}
}
public class ValuesController : ControllerBase
{
public ActionResult Index()
{
var vm = ...;
return ViewModelResult(vm);
}
}
Just to complete the answer of #Markus:
You can access the View method only by inheritance as you can see on the MSDN Controller.View Method
Extension methods are purely syntactic sugar and are replaced at compile time by your ExtensionController.ViewModelResult(this,viewModel);
Hence you can access only public modifiers if your extension class is not part of the library of the object you want to extend.
Related
I couldn’t find any similar issue so I’m writing this post. There is sample controller with private field IBaseClass. Sample code looks like follows:
public class TmpController : Controller
{
private IBaseClass _baseClass;
public TmpController()
{
_baseClass = new BaseClass(this);
}
}
public interface IBaseClass
{
//...
}
public class BaseClass : IBaseClass
{
protected TmpController TmpController;
public BaseClass(TmpController tmpController)
{
TmpController = tmpController;
}
//IBaseClass implementation
}
My question is; how to inject BaseClass object to the constructor of TmpController using Unity framework?
I want to make my controller "slimmer". I want to put the logic about validation and preparing dataSource of my controls like comboBox etc. to different class. I try to make some kind of SOC in my .Web project in that very specific case, which will make my controller easier to read and maintain. I'm using approach one controller per one view but I met the case with very complex form. Currently I have controller with more than 3000 lines of code and it's hard to maintain so I want to do something with it.
And yes I'm using Services and Repositories but the problem is about validation of ViewModels, mapping ViewModel objects into DTOs and backwards, preparing data source of given components etc.
#Razem, what you guess from my comment is correct. And the minus point you described is also valid.
What you are asking "Service depending on the controller" can surely be achieved but that would be a bad design.
Currently BaseClass is only dependent on TempController. How would you handle the scenario when you need the BaseClass in some other controller also? The code will start breaking and you will end up adding new dependency to BaseClass.
Also as per the design recommendations Top Layers should be dependent on the Bottom Layers not the vice versa.
Being said that, you can still achieve the feature you are looking for that too by making controller dependent on the IBaseClass.
I am not sure the specific reasons you need to access controller inside BaseClass. I have made certain assumptions while creating following suggestions. One of such assumption is BaseClass, IBaseClass and Controller classes are part of the same assembly.
//Have a BaseController Class with the properties and/or method which you will be using in the `BaseClass` class and make them virtual so that derived controller classes can override them to have specific implementation.
public class BaseController : Controller
{
public virtual string ControllerMethod()
{
return "Controller Method from Base Controller";
}
public virtual string RandomValue
{
get
{
return "Random value from Base Controller";
}
}
}
Create a method in IBaseClass which will Set the Controller for it.
public interface IBaseClass
{
void SetController(BaseController controller);
void Method1();
}
public class BaseClass : IBaseClass
{
private BaseController controller;
public void SetController(BaseController controller)
{
this.controller = controller;
}
public void Method1()
{
var str = this.controller.RandomValue;
}
}
And derive the TempController from the BaseController and make it dependent on IBaseClass. And in the constructor of TempController call SetController method of IBaseClass by passing this argument to it. You also can override method/properties of BaseController here.
After this you can call any method of IBaseClass without passing controller instance to it.
public class TempController : BaseController
{
private IBaseClass baseClass;
public HomeController(IBaseClass productService)
{
this.baseClass = productService;
this.baseClass.SetController(this);
}
public override string RandomValue
{
get
{
return "Random value from Derived Class.";
}
}
public ActionResult Index()
{
this.baseClass.Method1();
ViewBag.Title = "Home Page";
return View();
}
}
Install nuget package Unit.Mvc in your web project. Open file Unity.Config located under App_Start folder and change method RegisterTypes as following.
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IBaseClass, BaseClass>(new PerRequestLifetimeManager());
}
I am sure I don't need to explain how this is going to work.
P.S. : You need to make sure that you calls IBaseClass.SetController method in controller constructor to avoid NullReferenceException when you use controller in BaseClass. This is small overhead you need to take to achieve good and maintainable design.
I have something like this in almost every action:
public ActionResult Show(int object_id)
{
Object obj = ObjectRepository.ById(object_id);
if (obj == null)
{
throw new HttpException(404);
}
if (obj.SomeCheck)
{
throw new HttpException(403);
}
// processing
}
Question is how to move object getting (and throwing http exceptions) away from action and have something like this:
public ActionResult Show(Object obj)
{
// processing
}
UPD: Can't change ObjectRepository and model itself, it's used not only with ASP.NET but in other parts of the project.
One option is to refactor your boilerplate into a private method:
private object GetItem(object obj) {
Object obj = ObjectRepository.ById(object_id);
if (obj == null) {
throw new HttpException(404);
}
if (obj.SomeCheck()) {
throw new HttpException(403);
}
return obj;
}
Then:
public ActionResult Show(int object_id) {
object obj = GetItem(object_id);
// processing
}
As others have suggested you could write filters or invoke an AOP framework like PostSharp.
However, that might be a tall order for some. You might want to consider writing something simple, maintainable and fairly readable, that everyone on the team can immediately understand:
public ActionResult Show(int object_id)
{
SomeClass obj = Require<SomeClass>(object_id, assumption: o => o.SomeCheck);
// processing
}
//Perhaps: put this in a base controller or other common class
private object Require<T>(int id, Func<object, bool> assumption) where T : class
{
var o = ObjectRepository.ById(object_id) as T;
//Result is required
if (o == null) {
throw new HttpException(404);
}
//Verify assumption
if (!assumption(o)) {
throw new HttpException(403);
}
return o;
}
You might look at
Writing a custom filter attribute such as an AuthorizationAttribute or ValidateInputAttribute. They can be applied to the entire controller or to specify methods (actions). See http://msdn.microsoft.com/en-us/magazine/dd695917.aspx#id0070026 for an overview.
You might want to look at using PostSharp (Aspect-Oriented Programming framework) to inject suitable aspects into your methods.
Others have provided some good answers. Among them, I like the idea of using an action filter but unfortunately I don't believe it will work very well as you'll be forced to use property injection (or explicit instantiation - yuck!) for the repository, which I'd prefer to avoid. For this reason, I think a dedicated controller method is a better option.
I will throw one more idea in the hat, though.
You mentioned that you can't change ObjectRepository but you can always abstract it:
public class HttpObjectService /*: IObjectService */
{
private readonly /*I*/ObjectRepository _repository;
public HttpObjectService(/*I*/ObjectRepository repository)
{
if (repository == null) throw new ArgumentNullException("repository");
_repository = repository;
}
public Object ById(int id)
{
var obj = _repository.ById(id);
/* Check and throw HttpExceptions */
}
}
Then inject this into your controller. Whether or not you like the idea of a "web-specific" service that throws HttpExceptionsdirectly is a matter of taste but it is extremely reusable and, in this case, I believe it provides a cleaner separation of concerns than private validation methods in the controller.
The downside, of course, is that you're allowing your controller to delegate its responses (in the event of an error) directly to a third party. You may prefer your controller to have absolute control over this - that would be a reasonable criticism. In that case, you could always pass an ObjectValidator object into the constructor from the controller, which takes care of the validation. This would let your controller maintain control of what exceptions are thrown regardless of the service implementation.
You would have to be considerate of where this fits into your project architecture - it would probably belong in a separate assembly to your MVC project but one that is dedicated to web-based UIs.
In an attempt to DRY up my code today i'd like to do the following. (I don't know if its the best way, but it seems better than to have an ever increasing code base where I continually need to update multiple methods if i want to change something across the whole site)
What i know about Inheritance is scary. As Iv'e never questioned any of the code/libraries that I use, and Iv'e never really attempted writing anything like this before, but I want to learn... Hoping this will be my day of enlightenment :P
To my question:
Say Iv'e got an add method (in all my controllers) like this:
public ActionResult Add(VM_Down_Time_Capture viewModel)
{
using (Down_Time_CaptureRepository repository = new Down_Time_CaptureRepository())
{
if (!ModelState.IsValid)
return ReturnValidationFailure(ViewData.ModelState.Values);
Down_Time_Capture model = new Down_Time_Capture();
model.InjectFrom(viewModel);
string mserMsg = repository.Add(model, User.Identity.Name);
if (!string.IsNullOrEmpty(mserMsg))
return ReturnCustomValidationFailure(Server.HtmlEncode(mserMsg));
repository.Save();
return Json("Added successfully.", JsonRequestBehavior.AllowGet);
}
}
And at the moment I've got the following as well.
Generated by T4 Templates/EF.
ViewModels, Repositories, (Standard) EF Models
I'm thinking I need a ModelSpecfic base controller for each page (can be done using T4), that inherits from a custom ControllerBase class that contains the basic CRUD functionality. That way i can have custom code per controller, and my code base will be cleaner & smaller & that wont get affected should i need to regenerate the base files
I don't quite understand how to implement something in the lines of what i need. What i understand so far is that ill need to have my repositories, and view models inherit from a base as well and somehow specify in [B] which ones I'm using... but as to how to do that i don't know
For example (and this is my best attempt at it, not my actual code, extremely hacky as I'm amazingly confused :S)
public class Down_Time_CaptureController : Down_Time_CaptureBase
{
//[A]
}
//Generated by T4
public class Down_Time_CaptureBase: ControllerBase
{
//[B]
public override EntityObject CreateNewModel()
{
return new Down_Time_Capture();
}
public override Base_Repository CreateNewRepository()
{
return new Down_Time_CaptureRepository();
}
public override Base_ViewModel CreateNewViewModel()
{
return new VM_Down_Time_Capture();
}
//how would i go about specifying which repository & model & view model to use
//although i expect it to be something to what i did here above
//and how would i go about calling the new generic add method (but in context of this controller)?
}
//coded once
public abstract class ControllerBase: Controller
{
//[C]
//make abstract so i have to override it
public abstract Base_Controller CreateNewModel();
public abstract Base_Controller CreateNewRepository();
public abstract Base_Controller CreateNewViewModel();
//I'm assuming my generified add method would go in here
public virtual ActionResult Add(Base_ViewModel viewModel)
{
using (Base_Repository repository = CreateRepository())
{
if (!ModelState.IsValid)
return ReturnValidationFailure(ViewData.ModelState.Values);
EntityObject model = CreateNewModel();
model.InjectFrom(viewModel);
string mserMsg = repository.Add(model, User.Identity.Name);
if (!string.IsNullOrEmpty(mserMsg))
return ReturnCustomValidationFailure(Server.HtmlEncode(mserMsg));
repository.Save();
return Json("Added successfully.", JsonRequestBehavior.AllowGet);
}
}
}
Here's a simple generic interpretation of what you are asking for:
// concrete controller implementation
public class Down_Time_CaptureController: ControllerBase<Down_Time_Capture, VM_Down_Time_Capture, Down_Time_CaptureRepository>
{
}
// generic controller base
public abstract class ControllerBase<TModel, TViewModel, TRepository>: Controller
where TModel : Base_Model, new()
where TViewModel : Base_ViewModel, new()
where TRepository : Base_Repository, new()
{
protected virtual TModel CreateNewModel()
{
return (TModel)Activator.CreateInstance<TModel>();
}
protected virtual TRepository CreateNewRepository()
{
return (TRepository)Activator.CreateInstance<TRepository>();
}
protected virtual TViewModel CreateNewViewModel()
{
return (TViewModel)Activator.CreateInstance<TViewModel>();
}
//I'm assuming my generified add method would go in here
public virtual ActionResult Add(TViewModel viewModel)
{
using (var repository = CreateRepository())
{
if (!ModelState.IsValid)
return ReturnValidationFailure(ViewData.ModelState.Values);
var model = CreateNewModel();
model.InjectFrom(viewModel);
string mserMsg = repository.Add(model, User.Identity.Name);
if (!string.IsNullOrEmpty(mserMsg))
return ReturnCustomValidationFailure(Server.HtmlEncode(mserMsg));
repository.Save();
return Json("Added successfully.", JsonRequestBehavior.AllowGet);
}
}
}
A few notes:
You will probably want to create interfaces for the three types (Model, ViewModel, Repository) and use those as the generic constraints.
You will probably want a generic Repository interface and base implementation (so you don't have to code each repository independently, and copy similar logic from one to the other).
Consider using an Inversion of Control container and dependency injection. Rather than have the controller, for example, handle creating an instance of a repository, make it a property and set it from the constructor. You can then use an IoC of your choice (like Ninject or Autofac) and register concrete implementations, and it will manage creating and the lifetime of both the dependencies and the controller itself.
I've done alot of research, including here on SO, and I can't seem to find clear direction. I currently have an ASP.NET MVC3 application, with a service layer that sits on top of a repository.
In my service layer, I have functions such as:
public class MyService{
public void CreateDebitRequest(int userId, int cardId, decimal Amount, .... )
{
//perform some sort of validation on parameters, save to database
}
public void CreateCreditRequest(.....)
}
//perform some sort of validation on parameters, save to database
}
public void CreateBatchFile()
{
//construct a file using a semi-complex process which could fail
//write the file to the server, which could fail
}
public PaymentTransaction ChargePaymentCard(int paymentCardId, decimal amount)
{
//validate customer is eligible for amount, call 3rd party payments api call,
//...save to database, other potential failures, etc.
}
}
I've seen people say that parameter validation isn't very exceptional, and so throwing an exception is not very fitting. I also don't love the idea of passing in an out paramater, such as a string, and checking for an empty value. I've considered implementing a ValidationDictionary class, and making it a property of any given service class (it would contain an IsValid boolean, and a List of error messages, and could be checked after any given function call in the service layer to see how things went). I could check the ValidationDictionary status after running any given function:
var svc = new MyService();
svc.CreateBatchFile();
if (svc.ValidationDictionary.IsValid)
//proceed
else
//display values from svc.ValidationDictionary.Messages...
The thing I don't like about this is that I would have to update it for every service layer function call, to avoid having it retain old values (if I chose not to use it for many or most functions, one would still expect it to have a meaningful or null value after running any given function). Another thing I've considered is passing in the ValidationDictionary for each function call that might have detailed validation information, but then I am back to using an out parameter...
Do any of you have recommendations? I can't seem to figure out any clean way of doing this. Sometimes returning null for a function is enough information, but sometimes I'd like a little more validation information passed back to the caller. Any advice would be appreciated!
Edit to clarify:
My service layer is not aware that it is an MVC application that is consuming it. The service layer just has certain public functions such as CreateBatchFile() or AddDebitRequest(). Sometimes returning null is enough for the consumer (in this case a controller, but could be something else) to know what happened, and sometimes the consumer would like some more information from the service layer (maybe to pass along to ModelState if the consumer is a controller). How do I bubble this up from the service layer itself?
This is what I do. Have a class for your validation, and instead of passing parameters pass a view model. So in your case something like this, where ValidationResult is just a simple class w/ MemberName and ErrorMessage properties:
public class DebitRequestValidator{
public IEnumerable<ValidationResult> Validate(DebitRequestModel model){
//do some validation
yield return new ValidationResult {
MemberName = "cardId",
ErrorMessage = "Invalid CardId."
}
}
}
Then create a controller extension method to copy these validation results to the model state.
public static class ControllerExtensions
{
public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable<ValidationResult> validationResults)
{
if (validationResults == null) return;
foreach (var validationResult in validationResults)
{
modelState.AddModelError(validationResult.MemberName, validationResult.ErrorMessage);
}
}
}
Then in your controller do something like
[HttpPost]
public ActionResult DebitRequest(DebitRequestModel model) {
var validator = new DebitRequestValidator();
var results = validator.Validate(model);
ModelState.AddModelErrors(results);
if (!ModelState.IsValid)
return View(model)
//else do other stuff here
}
Then in your view you can display errors like normal.
#Html.ValidationMessageFor(m => m.CardId)
I used a system where it was passing an array of messages (or collection of classes), each element had codes, descriptions, friendly messages. We used to simply check if anything was there. It worked great between UI and another "service" layer, all exception were caught nicely, they were translated into these validation rules...just an idea
Use ViewModel objects that are passed between the Views and the Controller action methods. The ViewModel objects can handle Validation by a Validate(ValidationDictionary validationDictionary) method.
The controller will have to call the Validate method on ViewModel object before calling any method in the service layer. This should only be necessary for http POST actions.
Your views will then have to display validation messages.
This solution requires that the viewmodel objects are passed between the controller action and the view, but nowadays that is mostly handled by the ModelBinder in MVC.
Your controller (http post) actions will look something like this:
[HttpPost]
public ActionResult Foo(BarViewModel viewModel)
{
viewModel.Validate(ValidationDictionary);
if (!ModelState.IsValid)
{
return View(viewModel);
}
// Calls to servicelayer
}
Your Validate method in your ViewModel will look like this:
public void Validate(ValidationDictionary validationDictionary)
{
if (SomeProperty.Length > 30)
{
validationDictionary.AddError("SomeProperty", "Max length is 30 chars");
}
}
If you're just doing ViewModel Validation, FluentValidation is an excellent library.
If you're wanting to include business validation as feedback to the user, you could use the adapter pattern, it'll give you what you want.
Create an interface (IValidationDictionary or something similar). This interface would define an AddError method and would be passed to your service in order to add error messages.
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
}
Create a ModelStateAdapter for your mvc application.
public class ModelStateAdapter : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateAdapter(ModelStateDictionary modelState)
{
_modelState = modelState;
}
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
}
Your service calls that need validation would require the IValidationDictionary
public class MyService
{
public void CreateDebitRequest(int userId, int cardId, decimal Amount, .... , IValidationDictionary validationDictionary)
{
if(userId == 0)
validationDictionary.AddError("UserId", "UserId cannot be 0");
}
}
You would then have a dependency on IValidationDictionary but not on MVC which would also make your solution testable.
If you needed to implement the services in an app that didn't have a ModelStateDictionary, you would just implement the IValidationDictionary interface on a class used for holding your errors.
Controller example:
public ActionResult Test(ViewModel viewModel)
{
var modelStateAdapter = new ModelStateAdapter(ModelState);
_serviceName.CreateDebitRequest(viewModel.UserId, viewModel.CardId, ... , modelStateAdapter);
if(ModelState.IsValid)
return View("Success")
return View(viewModel);
}
Pro's of this approach:
No dependency on the calling libraries
It's possible to mock the IValidationDictionary for tests.
Con's of this approach:
You need to pass IValidationDictionary to every method that you want to do validation on that's going to be returned to the user.
Or
you need to initialise the service's validation dictionary (if you decide to have IValidationDictionary as a private field), in each controller action you want to validate against.
According to this tutorial, to use Ninject in my Asp.net MVC 3 application , all I have to do is install package via Nuget and configure dependencies.
Follow these steps
Install Package-Ninject.MVC3
In NinjectMVC3.cs
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IReCaptchaValidator>().To<ReCaptchaValidate>();
}
In Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Registe(RegisterModel model)
{
var myObject = DependencyResolver.Current.GetService<IReCaptchaValidator>(); //always null
}
myObject always returns null.
I've tried kernel.Bind<IReCaptchaValidator>().To<ReCaptchaValidate>().InRequestScope(), but not effect!
myObject continues null
In this post here on StackOverflow, I was told to use DependencyResolver.Current.GetService(TYPE) to retrieve the instance of an object.
In the post you refer to, you were not told to use DependencyResolver, just that it's possible to use it. You shouldn't use it, as it's a well known anti-pattern.
While using the DependencyResolver directly should work, you really shouldn't do it that way.
Instead, you should use Constructor Injection, which would be to have your class take the type as a parameter of your constructor.
public class MyController : Controller {
IReCaptchaValidator _validator;
public MyController(IReCaptchaValidator validator)
{
_validator = validator;
}
}
Then, in your method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Registe(RegisterModel model)
{
var myObject = _validator;
}
I had the same problem.
On the same function, I could resolve an interface just fine, while another interface did not resolve. They were both registered!
When resolving manually, it seems that you don't get errors!
Pretty funny, but I just found about!
Once I injected the interface in a controller constructor and enabled all exceptions, then I get an exception saying that there was no public constructor for my implementation!
Try that and you will most likely find the root cause.