Hello everyone as you can tell my still learning, I was wondering how or what is the best method to use in order to reuse my code for database actions ;for instance with the code below
// i reuse this code multiple times throughout my site but everytime I change it I must change
// all of the different Edit's each time I would like a central hub for all of it.
[Authorize]
public ActionResult Edit()
{
var ss = User.Identity.Name;
int myid = Convert.ToInt32(ss);
var buyer = (from s in db.buyers where myid == s.RegistrationID select s).FirstOrDefault();
ViewBag.RegistrationID = myid;
if (buyer != null && buyer.RegistrationID == myid)
{
return View(buyer);
}
else
{
RedirectToAction("buyerrequire");
}
return View("buyerrequire");
}
How can I put such code into a reusable container? so that if I change something there it will change all over that website where that container is used, sortoff like a _Partial except for ActionResults ... thanks for the help..
There are multiple ways of doing that.
1. You can have another base Controller for this purpose as follows:
public class SomeController : Controller{
// the code you use in multiple places.
}
Then the controllers which need these code, can extend this Controller.
You can have an [Attribute] for this functionality and you can decorate the methods with this attribute.
I would go for 2, this is also what asp.net mvc uses for common code such as attributes, logging, security etc.
Related
I have a simple scenario where if a cart is empty, I'd like to redirect to another 'page'(controller) which states the cart is empty or just send them back to the shop.
Heres my code:
public async Task<IViewComponentResult> InvokeAsync()
{
CartFunctions cartf = new CartFunctions(_logger, AppSettings, _httpContextAccessor);
Cart c = new Cart();
c = cartf.GetShopingCart();
if (c.CartItems == null)
{
// How do I get out of here to a differnet Controller
}
return View(c.CartItems);
}
If it was a controller I could return RedirectToAction
but that is not available here.
I think the main problem is i need to either get out OR return a Cartitems and I can't find a way to do both.
In the good ole days it was simple with response.redirect("Empty.aspx") but now that everything is 'easier' in MVC, it takes days of research to do the simplest things.
A view component does not sound like the ideal option do this redirect. View components are ideal for rendering some partial views. For example, rendering your cart item count or content, using the view component is a good idea.
In your case, you want to redirect to another action method when the cart is empty. You may create an action filter to do that. You can apply it on action method level or controller level as needed.
public class CheckCartValues : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (yourIfConditionToCheckCartIsEmpty)
{
context.Result =
new RedirectToRouteResult(new RouteValueDictionary(new {
controller = "Shop", action = "index" }));
}
base.OnActionExecuting(context);
}
}
You can apply it on the controller level
[CheckCartValues]
public class HomeController : Controller
{
}
Make sure you do not have it on the ShopController or you will get infinite redirects. You can also update the action filter code to not do the redirect when the current request is for the ShopController if needed. I will leave it up to you :)
If you want to use an attribute you can derive from ActionMethodSelectorAttribute https://msdn.microsoft.com/en-us/library/system.web.mvc.actionmethodselectorattribute.isvalidforrequest(v=vs.118).aspx#M:System.Web.Mvc.ActionMethodSelectorAttribute.IsValidForRequest(System.Web.Mvc.ControllerContext,System.Reflection.MethodInfo).
For example you could create an attribute named CartStatus(bool isEmpty) and apply the attribute to the method(s) that need to behave differently based on cart status. Then you have your conditional logic in exactly one place (this attribute) and you can reuse it across your application. Similar to #shyju's approach but instead of redirect you just return true/false from this method for the action that is appropriate.
currently i am doing a project in zend the way i am doing is working perfectly but i am sure its not the way i am suppose to do i mean i am not following MVC and i want to apply MVC in my zend app.
i am pasting code of one simple module which will describe what i am doing .kindly correct me where i am making faults.
my controller
class ContactsController extends Zend_Controller_Action{
public function contactsAction(){
if(!Zend_Auth::getInstance()->hasIdentity()){
$this->_redirect('login/login');
}
else{
$request = $this->getRequest();
$user = new Zend_Session_Namespace('user');
$phone_service_id = $user->p_id;
$instance = new Contacts();
$select = $instance->Get_Contacts($p_id);
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
$paginator = new Zend_Paginator($adapter);
.
.
//more code
}
plz note this 2 line in my controller
$instance = new Contacts();
$select = $instance->Get_Contacts($pid);
this is my contacts class in models
class Contacts extends Zend_Db_Table{
function Get_Contacts($p_id){
$DB = Zend_Db_Table_Abstract::getDefaultAdapter();
$select = $DB->select()
->from('contact', array('contact_id','contact_first_name','contact_mobile_no','contact_home_no','contact_email','contact_office_no'))
->where('pid = ?', $p_id)
->order('date_created DESC');
return $select;
}
}
after this i simple assign my result to my view.
note please
as its working but there is not private data members in my class,my class is not a blue print.there are no SETTERS AND GETTERS .how can i make my code that best suits MVC and OOP??
The most simple answer: you are already almost MVC. You use a Zend_Controller_Action to grab some data and pass this on to a view layer where you render the html. The only missing part is your model, which is mixed up between the controller and your data gateway (where you implemented a table data gateway pattern, that Zend_Db_Table thing).
I gave a pretty thorough explanation in an answer to another question how I'd properly set up the relations between Controller and Model. I also combined this with a Form, to handle data input, filtering and validation. Then to bundle some common functions, I introduced a Service layer between the Model and Controller.
With the controller, you perform some actions (list all my contacts, create a new contact, modify a contact) and the model is purely containing the data (id, name, phone, address). The service helps to group some functions (findContactByName, findContactById, updateContactWithForm).
If you know how to split Controller, Mode, Form and Service, your controller can become something like this:
class ContactsController extends Zend_Controller_Action
{
public function indexAction ()
{
if (!$this->hasIdentity()) {
$this->_redirect('login/login');
}
$service = new Application_Service_Contacts;
$contacts = $service->getContacts();
$paginator = $service->getPaginator($contacts);
$this->view->paginator = $paginator;
}
protected function hasIdentity ()
{
return Zend_Auth::getInstance->hasIdentity();
}
}
It is your personal taste what you want to do in your controller: I'd say you put as less as possible in your controllers, but you need to keep the control. So: a call to get data happens in the controller, retrieving this data happens somewhere else. Also: a call to convert a dataset into something else happens in the controller, the conversion happens somewhere else.
This way you can change the outcome in controllers extremely fast if you provided enough methods to your service classes to fetch the data. (Note I took the Zend_Auth to another function: if you have other actions, you can use this same function. Also, if you want to change something in your authentication, you have one place where this is located instead of every action in the controller)
keep one thing in mind when u learn new technology so first read thier own documentation. No one can explain better than them. Its hard to understand firstly but when you study it you will usedto and than u will love it like me Zend Offical Site
I am building an ASP.NET MVC3 computer support ticketing portal.
There is a maintenance state, where it is best to forbid the users from interacting with EF/Database, to avoid "collisions" I am currently getting.
I have an IMaintenanceDispatcher that has a boolean property IsOnMaintenance set to true by the business logic, whenever a background logic puts the portal in that state.
I need to redirect client requests to a parking page for the time of maintenance.
Where do I place the logic that will check if the IsOnMaintenance is true, and if so, do a redirect to a URL?
You could put it in an ActionFilterAttribute and apply that attribute to any applicable actions/controllers or globally.
public class IsOnMaintenanceAttribute : ActionFilterAttribute
{
//You'll need to setup your IoC to inject this
public IMaintenanceDispatcher InjectedMaintenanceDispatcher { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
object ticketIdObj;
if (!filterContext.ActionParameters.TryGetValue("ticketId", out ticketIdObj))
return;
//Make sure it exists
if (InjectedMaintenanceDispatcher.IsOnMaintenance(int.parse(ticketIdObj)))
{
var routeValues = new RouteValueDictionary(new {
action = "parkingpage",
controller = "maintenance",
area = "ticket" });
filterContext.Result = new RedirectToRouteResult(routeValues);
return;
}
}
}
Note, your action method parameters needs to contain a variable named ticketId for the filterContext.ActionParameters.TryGetValue to work.
Note: I had assumed that an individual ticket is put into maintenance mode and you were wanting to check for that... but re-reading the question it seems like you want to put the whole area/site on hold. Even with that case, the ActionFilterAttribute example still holds... just not as different.
I know how to get the current controller name
HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
But is there any way to get the current controller instance in some class (not in an action and not in a view)?
By default you can only access the current Controller inside a controller with ControllerContext.Controller or inside a view with ViewContext.Context. To access it from some class you need to implement a custom ControllerFactory which stores the controller instance somewhere and retrieve it from there. E.g in the Request.Items:
public class MyControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controller = base.CreateController(requestContext, controllerName);
HttpContext.Current.Items["controllerInstance"] = controller;
return controller;
}
}
Then you register it in your Application_Start:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
And you can get the controller instance later:
public class SomeClass
{
public SomeClass()
{
var controller = (IController)HttpContext.Current.Items["controllerInstance"];
}
}
But I would find some another way to pass the controller instance to my class instead of this "hacky" workaround.
Someone will have to correct me if what I am doing is detrimental to the whole Asp.Net page life cycle / whatever but surely you can do this:
In controller
ViewBag.CurrentController = this;
In view
var c = ViewBag.CurrentController;
var m1 = BaseController.RenderViewToString(c, "~/Views/Test/_Partial.cshtml", null);
In my case, I had a base controller that all controllers extend. In that base controller lived a static method called RenderViewToString and it required a controller. Since I figured I could just instantiate a new instance of an empty controller at this point for c, I just sent it to the view in the lovely ViewBag container that exists in the world of Asp.Net MVC. For reasons I could not go into now, I could not retrieve the string in the controller and send just that back to the view (this was what I had done earlier before requirements changed).
The reason I have done it this way is in other languages like PHP and JS, there are similar simple ways to transfer classes around.
We have an a PHP application that we are converting to MVC. The goal is to have the application remain identical in terms of URLs and HTML (SEO and the like + PHP site is still being worked on). We have a booking process made of 3 views and in the current PHP site, all these view post back to the same URL, sending a hidden field to differentiate which page/step in the booking process is being sent back (data between pages is stored in state as the query is built up).
To replicate this in MVC, we could have a single action method that all 3 pages post to, with a single binder that only populates a portion of the model depending on which page it was posted from, and the controller looks at the model and decides what stage is next in the booking process. Or if this is possible (and this is my question), set up a route that can read the POST parameters and based on the values of the POST parameters, route to a differen action method.
As far as i understand there is no support for this in MVC routing as it stands (but i would love to be wrong on this), so where would i need to look at extending MVC in order to support this? (i think multiple action methods is cleaner somehow).
Your help would be much appreciated.
I have come upon two solutions, one devised by someone I work with and then another more elegant solution by me!
The first solution was to specify a class that extends MVcRouteHandler for the specified route. This route handler could examine the route in Form of the HttpContext, read the Form data and then update the RouteData in the RequestContext.
MapRoute(routes,
"Book",
"{locale}/book",
new { controller = "Reservation", action = "Index" }).RouteHandler = new ReservationRouteHandler();
The ReservationRouteHandler looks like this:
public class ReservationRouteHandler: MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var request = requestContext.HttpContext.Request;
// First attempt to match one of the posted tab types
var action = ReservationNavigationHandler.GetActionFromPostData(request);
requestContext.RouteData.Values["action"] = action.ActionName;
requestContext.RouteData.Values["viewStage"] = action.ViewStage;
return base.GetHttpHandler(requestContext);
}
The NavigationHandler actually does the job of looking in the form data but you get the idea.
This solution works, however, it feels a bit clunky and from looking at the controller class you would never know this was happening and wouldn't realise why en-gb/book would point to different methods, not to mention that this doesn't really feel that reusable.
A better solution is to have overloaded methods on the controller i.e. they are all called book in this case and then define your own custome ActionMethodSelectorAttribute. This is what the HttpPost Attribute derives from.
public class FormPostFilterAttribute : ActionMethodSelectorAttribute
{
private readonly string _elementId;
private readonly string _requiredValue;
public FormPostFilterAttribute(string elementId, string requiredValue)
{
_elementId = elementId;
_requiredValue = requiredValue;
}
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (string.IsNullOrEmpty(controllerContext.HttpContext.Request.Form[_elementId]))
{
return false;
}
if (controllerContext.HttpContext.Request.Form[_elementId] != _requiredValue)
{
return false;
}
return true;
}
}
MVC calls this class when it tries to resolve the correct action method on a controller given a URL. We then declare the action methods as follows:
public ActionResult Book(HotelSummaryPostData hotelSummary)
{
return View("CustomerDetails");
}
[FormFieldFilter("stepID", "1")]
public ActionResult Book(YourDetailsPostData yourDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[FormFieldFilter("stepID", "2")]
public ActionResult Book(RoomDetailsPostData roomDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[HttpGet]
public ActionResult Book()
{
return View();
}
We have to define the hidden field stepID on the different pages so that when the forms on these pages post back to the common URL the SelectorAttributes correctly determines which action method to invoke. I was suprised that it correctly selects an action method when an identically named method exists with not attribute set, but also glad.
I haven't looked into whether you can stack these method selectors, i imagine that you can though which would make this a pretty damn cool feature in MVC.
I hope this answer is of some use to somebody other than me. :)