i have a class (in project by mvc4 razor on .net 4.5) and want to handle a Redirecting method on it and do not want inherit from controller class.
how can i handle this?it returns ActionResult to redirecting user in some cases like log outing
my main class:
public class SecuritySrv
{
public ActionResult Redirect()
{
return RedirectToAction("Logout", "Account", new { area = "" });
}
}
and i want to use it in some controllers like below:
public ActionResult AccountHome()
{
SecuritySrv SecurityService =new SecuritySrv()
if(.....)
return SecurityService.Redirect();
return view();
}
You can use this code anywhere, and you don't need an UrlHelper or access to the context, so you don't need to inherit the Controller class.
RouteValueDictionary rvd = new RouteValueDictionary
{
{"controller", "Profile"},
{"action", "Users"},
{"area", ""}
};
return new RedirectToRouteResult(rvd);
The RedirectToAction method of controller is just a helper for creating RedirectToRouteResult, you can create it by yourself in your class:
public class SecuritySrv
{
public ActionResult Redirect()
{
RouteValueDictionary routeValues = new RouteValueDictionary();
routeValues["action"] = "Logout";
routeValues["controller"] = "Account";
routeValues["area"] = "";
return new RedirectToRouteResult(routeValues);
}
}
And call this method from your controller in the way you wanted to.
Related
I am currently using the Request.Scheme and Request.Host to composite Uri object to get AbsoluteUri for my .net core MVC application.
Uri location = new Uri($"{Request.Scheme}://{Request.Host}");
string applicationRootURL = location.AbsoluteUri;
But this only works in a non-static method.
As I need to re-use this method in another controller, I am thinking to make this action method static. If I do that, the compiler will complaint about the Request.Scheme and Request.Host.
I am wondering what's other options I have to achieve this?
Thank you.
UPDATE:
This is what I have for ControllerA with ActionMethodA
public class ControllerA
{
public bool ActionMethodA()
{
Uri location = new Uri($"{Request.Scheme}://{Request.Host}");
string applicationRootURL = location.AbsoluteUri;
return false;
}
}
And in another ControllerB, I want to ActionMethodB to invoke ActionMethodA from ControllerA:
public class ControllerB
{
public void ActionMethodB()
{
var result = ActionMethodA();
}
}
Is creating an Extension Method to the ControllerA is the most proper way to handle this kind of scenario?
Thank you.
You can also define an extension method directly for the HttpRequest class and use the BuildAbsolute method of the UriHelper class to build the uri.
public static class HttpRequestExtensions
{
public static string GetURI(this HttpRequest request)
{
return UriHelper.BuildAbsolute(request.Scheme, request.Host);
}
}
And use it:
public IActionResult ContollerMethod()
{
var uri = Request.GetURI();
// your code
}
You can write an extension method to a controller or HttpContext object. In the following example I have added an extension method to the controller.
public static class ControllerExtensions
{
public static string GetURI(this Controller controller)
{
Uri location = new Uri($"{ controller.Request.Scheme}://{controller.Request.Host}");
string applicationRootURL = location.AbsoluteUri;
return applicationRootURL;
}
}
Once the extension method is written you can call it in the following manner.
public IActionResult Index()
{
var url = this.GetURI();
return View();
}
Make sure to import namespace of an extension method in your calling code
Assume for a moment that I have an abstract controller
public abstract class ResourceController<TResource> : ApiController where TResource: Resource,new()
{
[Route("{id}")]
[HttpGet]
public async Task<IHttpActionResult> FindById([FromUri] string id)
{
TResource resource = null;
// go fetch the resource from a database or something
return Ok(resource)
}
[Route("")]
[HttpPost]
public async Task<IHttpActionResult> Create(TResource resource)
{
TResource resource = null;
// go create the resource or something
return CreatedAtRoute("XXXXX", new { id = resource.Id }, resource);
}
// more methods
}
[RoutePrefix("foo")]
public class FooResourceController : ResourceController<Foo>
{
}
[RoutePrefix("baa")]
public class BaaResourceController : ResourceController<Baa>
{
}
public class Resource
{
public string Id { get; set; }
// some other properties all resources shared
}
At this stage all the actions work, except for creating a new resource. Without overriding the Create method in every subclass, how do I find the correct route of the FindById of the respective controllers from the ResourceController Create method?
For example, if I create a foo resource with id 123 then it would return foo/123. If I created a resource baa with id 456, then it woulds return baa/456.
I'm unable to name the route using attributes, since only one can exist for the application.
Had the same problem. I fixed it by using the Created method in combination with the calling url.
This will only work if yout post doesn't have a dedicated template
My get:
[HttpGet("{id:int}")]
public async Task<IActionResult> GetAsync(int id)
{
try
{
var codetabel = await _reader.GetAsync(id);
var model = Mapper.Map<TCodeTabelModel>(codetabel);
return OkResult(model);
}
catch ....
}
And post:
[HttpPost()]
public async Task<IActionResult> InsertAsync(TCodeTabelModel model)
{
if (!ModelState.IsValid)
return BadRequestResult(ModelState);
try
{
var entity = Mapper.Map<TCodeTabelEntity>(model);
var insertedEntity = await _writer.InsertAsync(entity);
return Created($"{Request.Path.Value}/{insertedEntity.Id}" , Mapper.Map<TCodeTabelModel>(insertedEntity));
}
catch ....
}
before I injected my classes into every Action of a Controller. Using this ModelBinder approach:
public class AccountViewModelBinder: IModelBinder
{
private const string sessionKey = "Account";
private readonly IViewModelFactory _viewModelFactory;
public AccountViewModelBinder(IViewModelFactory viewModelFactory)
{
_viewModelFactory = viewModelFactory;
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// get the Cart from the session
AccountViewModel account = (AccountViewModel)controllerContext.HttpContext.Session[sessionKey];
if (account == null)
{
account = _viewModelFactory.CreateAccountVm();//new Cart();
controllerContext.HttpContext.Session[sessionKey] = account;
}
return account;
}
}
Controller Action:
public ActionResult Index(HomeViewModel homeVm, AccountViewModel accountVm)
{
//do something here...
return View();
}
But I think it is es mess to do it on every action again and again because there are allways the same for one controller.
So, how can I inject session related classes into controller constructor using ninject. I can already inject classes into conroller constructor but not session related one.
You question is not so clear, either way:
You will also have to re-inject on every other controller with ninject.
Maybe you can have on your BaseController a method that handle binding with generics and call it when ever you need.
protected T BindModel<T>(T model, string sessionKey){
T account = (T)controllerContext.HttpContext.Session[sessionKey];
if (account == null)
{
account = _viewModelFactory.CreateAccountVm();//new Cart();
controllerContext.HttpContext.Session[sessionKey] = account;
}
return account;
}
or, you can inject it like the following:
Bind<AccountViewModel>().ToProvider<ViewModeProvider>().InRequestScope();
class ViewModeProvider: ViewModeProvider<AccountViewModel> {
protected override AccountViewModel CreateInstance(IContext context) {
//put the logic from above here
return account;
}
}
or
Bind<AccountViewModel>().ToMethod(
c => new AccountViewModel{/* your logic goes here*/}).InRequestScope();
or maybe I did not get you correctly
I create clean APS.NET MVC 4 project and I try make internationalization using this tutorial.
I have problem with using baseController, because when I run project, function from base controller isn't execute. Maybe I forget implement something...
BaseController
public class BaseController : Controller
{
protected override void ExecuteCore()
{
string cultureName = null;
//Attempt to read the culture cookie from Request
HttpCookie cultureCookie = Request.Cookies["_culture"];
if (cultureCookie != null)
cultureName = cultureCookie.Value;
else
cultureName = Request.UserLanguages[0]; //obtain it from HTTP
//Validation culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
//Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
base.ExecuteCore();
}
}
HomeController
public class HomeController : BaseController
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
}
You might want to override the Initialize method instead ExecuteCore.
Here is an explanation and a solution: ExecuteCore() in base class not fired in MVC 4 beta
I'm building a Web API service using OData, and would like to expose a method as an Action in the service as follows.
http://myServer/odata/myAction
I'm currently mapping the OData routes as follows:
Dim modelBuilder As ODataModelBuilder = New ODataConventionModelBuilder
modelBuilder.EntitySet(Of Product)("Products")
Dim myAction = modelBuilder.Action("myAction")
myAction.Parameter(Of String)("Parameter1")
myAction.Returns(Of Boolean)()
Dim model As IEdmModel = modelBuilder.GetEdmModel
config.Routes.MapODataRoute("ODataRoute", "odata", model)
This wonderful tutorial shows how to associate an action with an entity like this:
http://myServer/odata/Products(1)/myAction
Following the tutorial, I can then write the method for the action in the ProductsController class after creating the model with the following line:
Dim myAction = modelBuilder.Entity(Of Product).Action("myAction")
However, if I don't want to associate the action with an entity, where would I write the method for the action? Is there a DefaultController class I need to write?
We currently do not have support for this out of the box, but its very easy to do it yourself. Example below (This nice sample is actually from Mike Wasson which is yet to be made public :-))
------------------------------------------------------
// CreateMovie is a non-bindable action.
// You invoke it from the service root: ~/odata/CreateMovie
ActionConfiguration createMovie = modelBuilder.Action("CreateMovie");
createMovie.Parameter<string>("Title");
createMovie.ReturnsFromEntitySet<Movie>("Movies");
// Add a custom route convention for non-bindable actions.
// (Web API does not have a built-in routing convention for non-bindable actions.)
IList<IODataRoutingConvention> conventions = ODataRoutingConventions.CreateDefault();
conventions.Insert(0, new NonBindableActionRoutingConvention("NonBindableActions"));
// Map the OData route.
Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "odata", model, new DefaultODataPathHandler(), conventions);
--------------------------------------------------------------
// Implements a routing convention for non-bindable actions.
// The convention maps "MyAction" to Controller:MyAction() method, where the name of the controller
// is specified in the constructor.
public class NonBindableActionRoutingConvention : IODataRoutingConvention
{
private string _controllerName;
public NonBindableActionRoutingConvention(string controllerName)
{
_controllerName = controllerName;
}
// Route all non-bindable actions to a single controller.
public string SelectController(ODataPath odataPath, System.Net.Http.HttpRequestMessage request)
{
if (odataPath.PathTemplate == "~/action")
{
return _controllerName;
}
return null;
}
// Route the action to a method with the same name as the action.
public string SelectAction(ODataPath odataPath, System.Web.Http.Controllers.HttpControllerContext controllerContext, ILookup<string, System.Web.Http.Controllers.HttpActionDescriptor> actionMap)
{
if (controllerContext.Request.Method == HttpMethod.Post)
{
if (odataPath.PathTemplate == "~/action")
{
ActionPathSegment actionSegment = odataPath.Segments.First() as ActionPathSegment;
IEdmFunctionImport action = actionSegment.Action;
if (!action.IsBindable && actionMap.Contains(action.Name))
{
return action.Name;
}
}
}
return null;
}
}
--------------------------------------------------
// Controller for handling non-bindable actions.
[ODataFormatting]
[ApiExplorerSettings(IgnoreApi = true)]
public class NonBindableActionsController : ApiController
{
MoviesContext db = new MoviesContext();
[HttpPost]
public Movie CreateMovie(ODataActionParameters parameters)
{
if (!ModelState.IsValid)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
string title = parameters["Title"] as string;
Movie movie = new Movie()
{
Title = title
};
db.Movies.Add(movie);
db.SaveChanges();
return movie;
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}