Optional parameters at the beginning of route - c#

I'm trying to create a route that satisfies below two scenarios:
en-us/mycontroller/action/1
mycontroller/action/1
Basically what I need is the below rule. But it seems that the system is always expecting the locale parameter, even though it's optional.
[Route("{locale?}/[controller]/[action]")]
public class MyController : Controller
{
[Route("{id}")]
public IActionResult Action(int id) {
return View();
}
}
Any idea how I can create a rule that supports above scenarios?

Optional parameters in routes must be at the end. There's no way around that. However, there's an alternate way to handle it: just add multiple routes:
[Route("{locale}/[controller]/[action]")]
[Route("[controller]/[action]")]
Now it will respond to either way. FWIW, you might want to consider adding some constraints to the locale param, though, so it doesn't match everything.

Related

c# HTTP Post IHttpActionResult

I have two httppost method one is taking an a concrete class with is working fine. The other one is taking in an interface. When I use postman I get null for the interface method.Should I be able to send a model class to an interface do I need to use custom model binder and if I do where do I need to add it?
public IHttpActionResult InsertData([FromBody] DataLog _datalog)
public IHttpActionResult Insert([ModelBinder(typeof(IDataLog))] IDataLog _log)
I think this would answer your question as well.
Interfaces
Reason why you cannot use interface as an object is because there are no public accessors for them. They also cannot have fields. It is just signature of the properties, and methods.
Interfaces
cannot have implementation
cannot have modifiers public
cannot have virtual
Classes
Each class you define have public properties that have getters and setters. Setters are what sets the values of these public properties. You can use the interfaces and extend them to classes and use these classes as objects to receive the data
Good read about defining and implementing interfaces
Custom Model Binding in ASP with examples
I donĀ“t know if i understand your question. Anyway regarding the code i must say:
Do not use '_' to named your variables, classes, parameters...it is not CLS compliant.
https://learn.microsoft.com/en-us/dotnet/api/system.clscompliantattribute?view=netframework-4.8
Maybe you can use the letter 'D' following the SOLID principle. D as Dependency Inversion using the IOC to Dependency Injection.
https://en.wikipedia.org/wiki/SOLIDhttps://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
In case that you have only one return type within your method, instead of using generic ActionResults types you can do something like, just to understand the logic:
Instead of:
public ActionResult Index()
{
return View();
}
Do this:
public ViewResult Index()
{
return View();
}
Difference Between ViewResult() and ActionResult()
Do Async await (TAP ) pattern.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
Instead of:
public IHttpActionResult InsertData([FromBody] DataLog _datalog)
Make the code to compile faster like this, adding the HttpPost attribute, even knowing this is a POST action:
Do this:
[HttpPost]
public IHttpActionResult InsertData([FromBody] DataLog _datalog)
Hope those good practices helps you somehow! :)

Why does MVC ignore controller methods in inherited controllers?

... which may not really be the question at all, but that's what it looks like to me right now.
I have a controller structure that has several layers of inheritance. The base controller is the one that implements Controller and has a method called Create(Guid var1, DateTime? var2) and is called like /MyDomain/Create/00000-0000-0000-000000.
I'm currently trying to implement a method in a controller lower down in the inheritance tree with the signature Create() which takes a QueryString parameter. (/MyDomain/Create?otherVar=somevalue) However, ASP.NET decides this is not valid as an "endpoint" and throws an error message saying The parameters dictionary contains a null entry for parameter 'var1' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Create(System.Guid, System.Nullable`1[System.DateTime])'
I don't really know what is going on here. If I try to call another method on the same controller (with a name that is unique and not used higher up in the inheritance stack e.g. /MyDomain/DifferentMethod) it works without a problem.
My google-fu is coming up short on this problem.
So you have something like:
public abstract class BaseController{
[HttpGet]
public IActionResult Create(Guid var1, DateTime var2){..
}
and
public class SomeClassController : BaseController{
[HttpGet]
public IActionResult Create(){..
}
The problem is that you cannot have 2 routes with the same name and different signature.
This is because the routing don't know exactly where you want to go: with the url '/blalbalba/Create/' witch one you want?
The base class or the inherited once?
It's not so obvious.
Ps take a look on this answer:
ASP.NET MVC ambiguous action methods

Inheriting Route attribute messes up already existing actions in Web API

I am trying to inherit Route attributes from a base Controller exactly according to this. Though it seems to work correctly, but it messes up the previously working actions.
Below are a minimal example of my base and child controllers.
[RoutePrefix("api/{controller}")]
public class MyController<TEntity, TDto>: ApiController{
[HttpGet]
public IEnumerable<TDto> All(){
...
}
[HttpGet, Route("lookup")]
public virtual IEnumerable<TDto> LookupData(){
...
}
}
[RoutePrefix("api/entity")]
public class EntityController : MyController<Entity, DTO>
{
}
After implementing the route attribute inheritance, the api/entity/lookup action works but in case of api/entity (for All), ActionSelector returns 2 actions, both All, and LookupData, thus causing error.
I am not sure why it is selecting an action with Route attribute even in case of a regular route. What I should do differently? Or is there any robust way to write a ActionSelector for this problem?
Try adding empty [Route] to All method:
[HttpGet]
[Route]
public IEnumerable<TDto> All(){
...
}

MVC 3 Call Controller method directly but also invoke the ActionFilterAttribute?

How would you go about invoking the ActionFilterAttribute when you are calling a controllers method directly? Imagine the following:
public class ApiController : Controller {
public ActionResult CallSomething() {
return IsCalled();
}
[MyAction]
public ActionResult IsCalled() {
return View();
}
}
So the request comes into /Api/CallSomething, the CallSomething() method internally calls another method (in this case IsCalled()) but when that method is called the ActionFilterAttribute is invoked and runs.
At the moment the ActionFilterAttribute will only be invoked if it's part of the original request, which makes sense because then it's part of the whole MVC lifecycle and all I'm doing is just calling a method directly, I'd need to do a RedirectToAction if I wanted it to get fired by MVC. RedirectToAction alters the URL so this isn't suitable for my purposes.
I've poked about the System.Web.Mvc code but I can't see how or when its being invoked. I figure that if it can do it then so can I potentially using reflection. In this event the Views aren't relevant as I am override the ExecuteResult() to write my own content into the http response.
Anyway I've resigned myself to this maybe not being possible but I'd just thought it would be worth a try.
There is no practically correct way to achieve that. So don't attempt to do it. Controller actions shouldn't be calling themselves as in your example. Use a redirect in this case. Or have the client send the request directly to the second action if you don't want the redirect.
Oh and if you have some common functionality between those controller actions that you want to reuse, simply externalize this functionality into some other layer. There are many ways to provide common functionality in ASP.NET MVC 3 depending on the exact scenario.
The simplest way to do what you're talking about is just to factor out the functionality that you want to execute as a filter and ad-hoc. It doesn't make sense to force a filter to execute where it shouldn't be executing. But it might make sense to want to call some part of the filter ad-hoc. The simplest way to do this is with a plain old static method:
public class ApiController : Controller {
public ActionResult CallSomething() {
MyActionFilter.CommonStaticMethodThatIsAlsoUsedInTheNormalFilter();
return IsCalled();
}
[MyActionFilter]
public ActionResult IsCalled() {
return View();
}
}
You should be more specific about what you're trying to achieve, there might be other features of the framework that are a better fit.

MVC Controller Generic injection with AutoFac

I am fairly new to DI with Autofac and wonder if the following is possible
I want to create a generic controller and action that receives an
injected type.
I do not want an instance of the injected type, but just need its
type, which would be an inplementation of an expected interface.
I would also like to pass that generic type on to a ViewModel, but that is another subject altogether, however if some genious out there can solve both that would be excellent.
public ContractorController<T> : Controller
where T : IContractor{
public ViewResult New() {
var vNewModel = new NewViewModel<T>();
return View(vNewModel);
}
}
This controller should be called through
http://mysite.com/Contractor/New
I have been looking into registering generics with AutoFac, but it
seems that the problem is that the AutofacControllerFactory only implements GetControllerInstance(), expecting the controller Type passed to it from either GetController() or CreateController(), not sure which or what the diffirence is between them. These methods receive the controller's name as a string from RoutData and return the corresponding .NET type which, give the url, http://mysite.com/Contractor/New is controller=Contractor and thus ContractorController cannot be matched by GetController() or CreateController() and therfore passing null to GetControllerInstance() which mean AutofacControllerFactory does not attempt to resolve the type.
I figured that I would have to create a custom Controller Factory
deriving from AutofacControllerFactory, override GetController() or CreateController() and
perform my own mapping from the controller names to the generic types.
Something like
if (controllerName == "Contractor")
return System.Type.GetType(
"UI.Controllers." + controllerName + "Controller`1");
When I debug this I can see that this code is finding the generic controller and returning it.
I thought I could then just register the types like
builder.RegisterType<FakeContractor>().As<IContractor>();
builder.RegisterGeneric(typeof(ContractorController<>));
But I am getting the following error
The Autofac service
'UI.Controllers.ContractorController`1'
representing controller
'ContractorManagement.UI.Controllers.ContractorController`1'
in path '/Contractor/New' has not been registered.
So I think I may be barking up the wrong tree.
Can anyone please shed some light on how I can do this without pulling
my teeth
Thank you
I'm not entirely sure why you want a controller using a generic. Using a generic on a Controller isn't really supported in Mvc - or at least the supporting routing path would be involved. Perhaps you can provide more info on the reasoning behind the approach?
What it looks like is that you want a controller that supports model binding against varying types. The next question is whether these types vary across a common interface or base class.
If that's the case, for Mvc2 check out the IocModelBinder information. This will work with Autofac quite well. This will allow the type to be model bound on post or get allowing you to inject services with autofac.
If you want to vary the types by a common base - supporting a variety of concrete view model - then check out the DerivedTypeModelBinder in MvcContrib. There is a version that works in Mvc 1, 2 and now MvcContrib for Mvc3 has a good sample app to accompany it. The Mvc3 implementation is also faster - speed wasn't a problem before, it's just a more efficient identification process.
Maybe it's not a direct answer to your question, but this is the only possible way to use generic controllers that I ever seen and used:
public abstract class ContractorControllerBase<T> : Controller where T : IContractor {
public ViewResult New() {
var vNewModel = new NewViewModel<T>();
return View(vNewModel);
}
}
public class FakeContractorController : ContractorControllerBase<FakeContractor> {
}

Categories