Reusing code in controllers - asp.net-mvc

I have a block of code which is use in pretty much every controller, so I am wondering how, or what's the best practice for reusing code in multiple controllers
Simple example would be this
public String CoolCode(){
// Stuff
return MyStuff;
}
Then in another controller I just use
string something = CoolCode();
Where should I put it, and how to use it in every controller?

Personally I would inject the helper class into the controller:
public interface IHelper
{
string CoolCode();
}
public class Helper : IHelper
{
public string CoolCode()
{
return "Cool code";
}
}
public class SomeController
{
private IHelper _helper;
public SomeController(IHelper helper)
{
_helper = helper;
}
public ActionResult Index()
{
//call _helper.CoolCode();
}
}
Then you would need to inject this using some sort of IoC container, I recommend Castle Windsor
This is all quite abstract but I recommend you read up on it:
http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be

What you should do is extend the Controller class that all your controllers inherit now and use this abstraction to wrap all of your controllers that use that code:
public class MyControllerBase : Controller
{
public string CoolCode() { ... }
}
now you simply inherit your abstraction rather than the default one:
public class AnyController : MyControllerBase
{
...
}
However depending on what you need precisely different approaches might be more appropriate.

public interface IBaseUserController
{
string SomePropety { get; set; }
ActionResult SignUp(string code, [Form] SomeViewModel model);
}
public class BaseUserController : Controller, IBaseUserController
{
private static string _somePropety = "";
public BaseUserController(){}
public string SomePropety
{
get
{
return _somePropety;
}
set { _somePropety = value; }
}
public virtual ActionResult SignUp(string code, [Form] SomeViewModel model)
{
// ... CoolCode maybe use SomePropety
return View(model);
}
}
public class TestUserController : BaseUserController
{
public TestUserController()
{
SomePropety = "Value";
}
public override ActionResult SignUp(string code, [Form] SomeViewModel model)
{
return base.SignUp(code, model);
}
public ActionResult SignUp2(string code, [Form] SomeViewModel model)
{
return base.SignUp(code, model);
}
}

MVC controller are same as normal class and controller have the same extension .cs
So use can use static method like following.
HomeController objHomeController = new HomeController();
string something= objHomeController.CoolCode();

Related

ViewBag in static method of controller

I am new to mvc and I load ViewBag in a method of controller as,
HomeController: Controller
{
Public ActionResult Index()
{
loadViewBag();
return View();
}
public void loadViewBag()
{
ViewBag.aaa = "something";
}
}
It works fine.
What is my problem is, Now I want to call loadViewBag() method form another controller( say Account) so that I can reuse same method and need to make loadViewBag() method static due to some static variables as:
public static void loadViewBag()
If I make loadViewBag method static, there appear error on ViewBag " An object reference is required for the non-static field, method, or property 'System.Web.Mvc.ControllerBase.ViewBag.get' ".
Is there any solution/suggestion.
Thank You.
Just make it an extension method of ControllerBase e.g.
public static void ControllerExt
{
public static void LoadViewBag(this ControllerBase controller)
{
controller.ViewBag.aaa = "something";
...
}
}
That way you can use it in any controller
public class HomeController : Controller
{
public ActionResult Index()
{
this.LoadViewBag();
return View();
}
}
public class AccountController : Controller
{
public ActionResult Index()
{
this.LoadViewBag();
return View();
}
}
If its only specific to some controllers then it would be more flexible to pass the ViewBag property in e.g.
public static class ControllerHelper
{
public static void LoadViewBag(dynamic viewBag)
{
viewBag.aaa = "something";
}
}
public class HomeController : Controller
{
public ActionResult Index()
{
ControllerHelper.LoadViewBag(ViewBag);
return View();
}
}
ViewBag is a property of your controller (more specifically of ControllerBase), and since a static method has no knowledge of a class instance, you can't access it.
You could pass the controller instance to the method if you want to use a static method or even make it an extension method, but depending on your problem, this solution could be sub-optimal. You may be able to get a better answer if you add more details to your question.
Public ActionResult Index()
{
this.loadViewBag();
return View();
}
public static void loadViewBag(this ControllerBase target)
{
target.ViewBag.aaa = "something";
}
Do you need that to allow different controllers/views to use some common properties?
Then I'd rather recommend a common base controller, while also wrapping ViewBag code into type safe properties (to let the compiler control the data consistency - as you know, ViewBag is not type safe, so any typos and data mismatches won't be noticed until the code gets executed).
1. Introduce a common controller with those wrapper properties
public abstract class MyBaseController : Controller
{
internal long CurrentUserId
{
get { return ViewBag.CurrentUserId; }
set { ViewBag.CurrentUserId = value; }
}
internal Role CurrentUserRole
{
get { return ViewBag.CurrentUserRole; }
set { ViewBag.CurrentUserRole = value; }
}
...
}
Thus, your inherited controllers could simply set the properties - or, with lots of common code just introduce a method in your base controller - similar to what you already have.
2. Introduce a common view class with those wrapper properties
public abstract class MyBaseViewPage<T> : WebViewPage<T>
{
public string Title
{
get { return (string)ViewBag.Title; }
set { ViewBag.Title = value; }
}
public long CurrentUserId
{
get { return (long)ViewBag.CurrentUserId; }
}
public Role CurrentUserRole
{
get { return ViewBag.CurrentUserRole; }
}
}
public abstract class MyBaseViewPage : MyBaseViewPage<dynamic>
{
}
and update web.config to let MVC know you're using a custom base view:
<configuration>
...
<system.web.webPages.razor>
...
<pages pageBaseType="MyRootNamespace.Views.MyBaseViewPage">
...
</pages>
</system.web.webPages.razor>
Now you can use them as normal properties in your controllers and views.

How to pass the delegate object to MVC Views.?

I have an delegate in my controller And I want that to be passed to my views to pass into my settings.
I have tried assigning delegates to ViewData["delegateFunction"]=delegateFunction;
But That too is not valid idea..
I know this is a basic Question. But just learning about delegates.
Thanks in advance,
saravanakumar.
I use the Model class for passing delegates to the View:
Model
public class ExampleModel
{
public Func<string, string> getUIName { get; set; }
}
Method declaration
public string concreteMethod_GetUIName(string text)
{
return text;
}
Controller
public ActionResult Index()
{
ExampleModel model = new ExampleModel { getUIName = concreteMethod_GetUIName };
return View(model);
}
View
#model ExampleModel
#Model.getUIName("sample text")

How to get Controller Name and its properties in another class?

I am developing a MVC application.
I want to send a controller for validating purpose to Validation class.
That class will validate the controllers properties and send the result.
I am not gettting, how to get name and properties of the controller after
getting it in class.
Below code is the Controller class code and I send this controller to class named validation class.
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
Validations v = new Validations();
Boolean ValidProperties = true;
//Sends the controller to Validation class
v.ValidProperty(this);
if (ValidProperties == true)
{
db.Locations.Add(location);
db.SaveChanges();
return RedirectToAction("Index");
}
}
}
And Below code is the class named Validations where I want to validate the controller .
Now I am not getting how to get the name of controller and its properties.
public class Validations
{
string PropertName;
public void ValidProperty(Controller ctr)
{
var name1 = ctr;
string s = ctr. ????????
//How to get Controller Name and its properties ?
}
}
use reflection to get name as:
var name = this.GetType().Name;
Or you can create a custom base controller of your choice, add properties, methods to it and deal with derived controllers as:
public abstract class BaseController : Controller
{
// add other properties as needed
public abstract string Name { get; protected set; }
public virtual void ValidProperty()
{
string s = Name;
//something esle
}
}
public class YourController : BaseController
{
private string _name;
public override string Name
{
get { return _name; }
protected set { _name = "Your_Name"; }
}
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
bool validProperties = true;
// Deals with a base controller method
ValidProperty();
// or something like this, if you prefer
var controller = (BaseController) this;
Validations v = new Validations();
//Sends the controller to Validation class
v.ValidProperty(controller);
if (validProperties)
{
db.Locations.Add(location);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return Content(string.Empty);
}
}

ASP.NET MVC Ninject / DI - No parameterless constructor defined for this object

I am using trying to get my head round unit testing with DI/Mocks (Ninject/Moq) to inject a Product repository into my controller which I then pass to my view model in order to allow testing of that.
It is working great and is allowing me to unit test the controller action and the view model. However, when I run the application I get "No parameterless constructor defined for this object"....now I know this is due to the controller trying to initialise the View Model which doesn't have a parameterless constructor.
I could create the constructor and call my concrete repository from that (so unit tests still use the injected/mocked one).
Is this the correct approach? Any advice would be greatly appreciated!
Controller:
public class ProductsController : Controller
{
private readonly IProductRepository productRepository;
public ProductsController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
//
// GET: /Products/
public ActionResult Index(ViewModels.ProductsIndex vm)
{
return View(vm);
}
}
View model:
public class ProductsIndex
{
public List<CTEntities.Product> ProductList { get; set; }
public ProductsIndex(IProductRepository prods)
{
ProductList = prods.List().ToList();
}
//Adding this constructor would fix my issue but is there a cleaner way?
public ProductsIndex()
{
var prod = new CTDAL.Product();
ProductList = prod.List().ToList();
}
}
Your View Model should be a DTO (Data Transfer Object) ... in that it should only contain properties, and it should NOT be responsible for getting data. Your controller should get the data for the View Model, like so:
New View Model:
public class ProductsIndex
{
public List<CTEntities.Product> ProductList { get; set; }
}
New Controller:
public class ProductsController : Controller
{
private readonly IProductRepository productRepository;
public ProductsController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
//
// GET: /Products/
public ActionResult Index()
{
var products = productRepository.List().ToList();
return View(products);
}
}
One approach would be to let Ninject resolve your ProductsIndex instances. If you do that, it will automatically fill in the constructor arguments as required, provided IProductRepository is resolved using Ninject as well.
In your case could be something like:
Kernel.Bind<IProductRepository>().To<CTDAL.Product>();
Kernel.Bind<ProductsIndex>().ToSelf();
Now your ProductsController could look like this:
public class ProductsController : Controller
{
private readonly IProductRepository productRepository;
private readonly ProductsIndex productsIndex;
public ProductsController(IProductRepository productRepository,
ProductsIndex productsIndex)
{
this.productRepository = productRepository;
this.productsIndex = productsIndex;
}
//
// GET: /Products/
public ActionResult Index()
{
return View(productsIndex);
}
}
Keep in mind that this would not allow for request values to be mapped to your Viewmodel, so the data in your Viewmodel would only be dependent on the parameters you pass into it at the time you resolve it (in this case the product repository).

ASP.NET MVC dependency injection and helpers

In asp.net MVC, dependency injection with controllers is simple and straightforward. Now, I'd like to remove most of the logic from views by using helpers. The problem is that these helpers use some of the objects that are injected.
Let me write an example:
public interface ISessionData
{
List<string> IdList {get;}
}
public MyController : Controller
{
public MyController(ISessionData sessionData)
{
...
}
}
session data is injected into controller. So far so good. But now I have a helper. Let's say it looks like this:
public class MyHelper
{
private readonly ISessionData sessionData;
public MyHelper(ISessionData sessionData)
{
this.sessionData = sessionData;
}
public bool CheckSomethingExistsInSession(string id)
{
return sessionData.IdList.Any(x => x.Id.Equals(id));
}
}
Now what? I'd like MyHelper to be injected into view. Only way I can see is adding this helper to model and passing it to view every time. Any other ideas?
In MVC it is better to pass ISessionData data from Controller to View (using ViewModel or ViewData):
ViewData["Session"] = sessionData.IdList.ToList();
And remove ISessionData dependency from the helper. Something like this:
public class MyHelper
{
//private readonly ISessionData sessionData;
public MyHelper(/*ISessionData sessionData*/)
{
//this.sessionData = sessionData;
}
public bool CheckSomethingExistsInSession(string id, IList<...> sessionData)
{
return sessionData.Any(x => x.Id.Equals(id));
}
}
In View:
<% var somethingExists = new MyHelper().CheckSomethingExistsInSession(
1, ViewData["Session"] as IList<...>); %>
UPDATED:
public static class MyHelper
{
public static bool CheckSomethingExistsInSession(string id, IList<...> sessionData)
{
return sessionData.Any(x => x.Id.Equals(id));
}
}
<% var somethingExists = MyHelper.CheckSomethingExistsInSession(
1, ViewData["Session"] as IList<...>); %>
You should remove session logic from your controller's constructor and insert it into the controllers action method by using an IModelBinder. See below:
public class SessionDataModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Get/create session data implementating ISeesionData or whatever here. This will be return to the controller action method.
return new SessionData()
}
}
On you controller you would do something like:
public MyController : Controller
{
public MyController()
{
....
}
public ActionResult Index(ISessionData sessionData)
{
// do stuff with ISessionData.
// Redirect or whatever.
return this.RedirectToAction("Index");
}
}
You need to add your IModelBinder like below for it to be called. You can do this in the http application's startup.
System.Web.Mvc.ModelBinders.Binders[typeof(ISessionData)] = new SessionDataModelBinder();

Resources