Let's say I have following simple controller:
public class DataController: Controller
{
[HttpGet]
public ActionResult Index()
{
// some code
}
}
Now I'd like Index action to be allways called if there is a GET request to DataContoller. I other words to ignore action name and any other parameters. For example all of following calls should be handled by Index action:
https://localhost:5000/data
https://localhost:5000/data/anything
https://localhost:5000/data/anything/secondAnything
https://localhost:5000/data/anything?someParameter=3
How can I achieve this?
You should update your RouteConfig like so:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
name: "RouteOverwrite",
url: "data/{*catchall}",
defaults: new { controller = "Data", action = "Index" }
);
}
}
Make sure you use this in Application_Start:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
// register route config
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
you can do this by using routetable. check out system.web.routing in asp.net mvc.
Related
I have an MVC app which has the following route config
In Global.ascx
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
In the RouteConfig.cs I have
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Now if i type in the browser , https://localhost/users this will take me to the
UsersController and call the Index() ActionResult. In there i do a check to see if the
user has access to the view or not as follows:
public ActionResult Index()
{
if (<User has access condition check>)
{
return View();
}
return View("~/Views/PermissionError.cshtml");
}
The issue is that I have about 30 pages in my app that the user can browse to by typing in the broswer url.
So instead of doing the check in every Index ActionResult , is there a way i can do the check in my route config or somewhere else that does the permission check and if they are allowed to view the page it will continue to the page
else it will show the error page ?
is there a way i can do the check in my route config or somewhere else that does the permission check
Yes, that might write a customer AuthorizeAttribute to make it.
You can try to write a customer AuthorizeAttribute and register that to global filter setting.
Here is the sample code which you can edit by your real logic.
public class AuthorizeBrowsingAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var isAnonAllowed = filterContext.ActionDescriptor.IsDefined(
typeof(AllowAnonymousAttribute), true) ||
filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
typeof(AllowAnonymousAttribute), true);
// user did't get
if (!<User has access condition check> && !isAnonAllowed)
{
filterContext.Result = new RedirectResult("~/Views/PermissionError.cshtml");
}
}
}
The code register our customer AuthorizeAttribute
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeBrowsingAttribute());
}
If there are some page which you don't want to do permission check you can add AllowAnonymous attribtue on the view method.
[AllowAnonymous]
public ActionResult NoPermission()
{
}
My Web API on an Asp.Net MVC web app is returning 404 error when receiving requests that don't specify any controller.
The calls that are returning 404 error are:
https://myWebApp/api/
The goal would be to handle these type of requests without returning error and return something like "true" or "new EmptyResult()".
Current routing for the Web API includes the following in WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new IdentityBasicAuthenticationAttribute());
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
While I have routes explicitly defined for each API controller:
[IdentityBasicAuthentication]
[Authorize]
public class myApi1Controller : ApiController
{
[HttpGet]
[Route("api/myApi1")]
public string Get(string id) { ... }
}
I have tried to route these calls to a default API or MVC controller without success.
My current RouteConfig for the MVC app is:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myWebApp.Controllers" }
);
}
}
The order in which these are called is:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Create a controller to handle that route so it does not fail with not found
Like
[RoutePrefix("api")]
public class MyEmptyController : ApiController {
//GET api
[HttpGet]
[Route("")]
public IHttpActionResult Get() {
return StatusCode(HttpStatusCode.NoContent); //204
}
}
Using attribute routing as it is already enabled via config.MapHttpAttributeRoutes(); in WebApiConfig
Your route config is different from your WebApi config and I don't know the order that you are calling them.
in your RouteConfig:
url: "{controller}/{action}/{id}",
which means: http://localhost:PORTNUMBER/myApi1/ACTION
in your WebApiConfig
routeTemplate: "api/{controller}/{id}",
(method and id are optionals)
which means: http://localhost:PORTNUMBER/api/myApi1/?id=value
change your WebApiConfig, and you even will be able to avoid using the Route tag in your controller :
[IdentityBasicAuthentication]
[Authorize]
public class myApi1Controller : ApiController
{
[HttpGet]
public string Get(string id) {
return "works!";
}
}
Edit:
Keep every thing the same, Invoke your default GET method from:
http://localhost:PORTNUMBER/api/myApi1
namespace ProjectA.Controllers
public partial class CustomerController : Controller
{
public virtual IActionResult Index()
{
...Some code here
}
public virtual IActionResult Login()
{
...Some code here
}
}
namespace ProjectB.Controllers
public partial class CustomerController : ProjectA.Controllers.CustomerController
{
public override IActionResult Login()
{
...Some code here
}
}
When I try to override as above it gives me below error
AmbiguousActionException: Multiple actions matched.
The following actions matched route data and had all constraints satisfied:
ProjectA.Controllers.CustomerController.Index (ProjectA)
ProjectB.Controllers.CustomerController.Index (ProjectB)
Though there is no Index action in ProjectB. When I change the name of the conroller of ProjectB as:
namespace ProjectB.Controllers
public partial class CustomCustomerController : ProjectA.Controllers.CustomerController
{
public override IActionResult Login()
{
...Some code here
}
}
AmbiguousActionException is gone but still the override doesnt work. I dont get call in overriden action.
Is it like .Net core doesnt support overriding any more because it works like charm without .net core with the same name of controllers.
Please help..
As you have both class name as “CustomerController”. And both may have using default routing. So for both controllers url should be same as /{controller}/{action}.
So for same url there will be 2 actions available for each controllers. That is why you are getting
“AmbiguousActionException” exception.
When you change your child controller to “CustomCustomerController” then url will be changed for both controllers so no such ambiguity happen so it worked.
As you said override not working. In this case you have to use url as “/CustomCustomer/login” then it will go to Login action of CustomCustomerController.
EDIT 1
You can update your code as below and it should work fine. Create your controllers as below:
namespace ProjectA.Controllers {
public partial class CustomerController : Controller
{
public virtual IActionResult Index()
{
...Some code here
}
public virtual IActionResult Login()
{
...Some code here
}
}
}
namespace ProjectB.Controllers {
public partial class CustomCustomerController : ProjectA.Controllers.CustomerController
{
public override IActionResult Login()
{
...Some code here
}
}
}
And Update app.UseMvc(routes => part into startup.cs as below. Add customer route before default route.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "customer",
template: "customer/{action}/{id?}",
defaults: new { controller = "CustomCustomer", action = "Index" });
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
I want use AnotherController name in SomeController.
But, RoutePrefix Attribute is can only be declared by Controller level.
Prepare the following.
namespace KRSMART.Controllers
{
public class SomeController : Controller
{
/* localhost:0000/Some/Index */
public ActionResult Index()
{
return View();
}
/* I want Url */
/* localhost:0000/Another/Test */
[Route("Another/Index")]
public ActionResult Test()
{
return View();
}
}
}
It didn't work as I wanted it to.
I know I can create a new controller and do it, but I didn't want to.
I'd like to get some advice from you who are familiar with Route.
You need to add routes.MapMvcAttributeRoutes(); before default route register,
your RegisterRoutes function should be like,
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: “Default”,
url: “{controller}/{action}/{id}”,
defaults: new { controller = “Home”, action = “Index”, id = UrlParameter.Optional }
);
}
I have applied attribute routing on my controller and it'srouting to wrong action. I don't know where I am getting it wrong.
Here is my controller:
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Description;
using System.Linq;
using System;
namespace Iboo.API.Controllers
{
public class ClientsController : ApiController
{
private readonly IClientRepository _repository;
public ClientsController(IClientRepository repository)
{
_repository = repository;
}
// GET: api/Clients
[Route("api/v1/clients")]
public IEnumerable<Client> Get()
{
//code
}
// GET: api/Clients/5
[HttpGet]
[ResponseType(typeof(Client))]
[Route("api/v1/clients/get/{id}")]
public IHttpActionResult GetClientById(int id)
{
//code
}
// GET: api/Clients/5
[HttpGet]
[ResponseType(typeof(string))]
[Route("api/v1/clients/{id}/emailid")]
public IHttpActionResult GetClientEmailId(int id)
{
//code
}
}
}
I am specifically interested in the GetClientEmailId method. Below is my WebApiConfig
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = new UnityContainer();
container.RegisterType<IClientRepository, ClientRepository>(new
HierarchicalLifetimeManager());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
My Global.asax.cs is as follows
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
In the browser If I type http://localhost:54919/api/v1/clients/?id=1/getemailid it's taking me to http://localhost:54919/api/v1/clients which is not what I want.
If I try http://localhost:54919/api/v1/clients/1/getemailid I am getting a 404 error.
I am not sure as to what I'm getting wrong.
You are calling the wrong URLs according to routes on the actions. you get 404 because the URL you call does not match to any of the route templates you have on your actions
[RoutePrefix("api/v1/clients")]
public class ClientsController : ApiController {
//...other code removed for brevity
[HttpGet]
[Route("")] //Matches GET api/v1/Clients
public IHttpActionResult Get() {
//code
}
[HttpGet]
[ResponseType(typeof(Client))]
[Route("{id:int}")] //Matches GET api/v1/Clients/5
public IHttpActionResult GetClientById(int id) {
//code
}
[HttpGet]
[ResponseType(typeof(string))]
[Route("{id:int}/emailid")] //Matches GET api/v1/Clients/5/emailid
public IHttpActionResult GetClientEmailId(int id) {
//code
}
}
Take note of the expected URLs in the comments
You should also read up on Attribute Routing in ASP.NET Web API 2 to get a better understanding of how to do attribute-routing.
You can try using the route prefix on the controller.
[RoutePrefix("api/v1/clients")]
public class ClientsController : ApiController
{
// GET: api/Clients/5
[ResponseType(typeof(string))]
[Route("{id:int}/emailid"),HttpGet]
public IHttpActionResult GetClientEmailId(int id)
{
//code
}
}
You said:
In the browser If I type http://localhost:54919/api/v1/clients/?id=1/getemailid it's taking me to http://localhost:54919/api/v1/clients which is not what I want.
From the way your routes are set up, it looks like you need to go to http://localhost:54919/api/v1/client/1/emailid to get to the route you want
To explain the difference, when you call http://localhost:54919/api/v1/clients/?id=1/getemailid the route that would match that is something like:
[Route("api/v1/clients")]
public IHttpActionResult GetClientEmailId(string id)
{
//code
}
because you've added the id parameter as a querystring parameter. In this case, the id argument would have a value of 1/getemailid which doesn't make much sense.
by using the route parameters (by replacing ?id=1/getemailid with 1/emailid) you will actually match the route you want to