... 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
Related
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! :)
This question already has an answer here:
Controller without the controller suffix
(1 answer)
Closed 7 years ago.
While reading this question today and making same mistake in past myself, I wondered if it's required (due to default convention?) that we MUST suffix "Controller" to a class name that is derived from Controller class in ASP.NET MVC, why compliler does not complain at all? At least a warning would save someone's time.
So below code will not work:
public class Search : Controller
{
// GET: /Search/
public ActionResult List()
{
var model = new MyModel();
return View(model);
}
}
So my question are:
Can we change this convention i.e. can I change setting somewhere and make suffix text 'MvcController' instead?
More important one, What is the reason C# compiler doesn't complain? It can not figure it out or it is not desired/illogical?
The question and answer does not answer both of my question so I think it is not exact duplicate.
The question you link to points out exactly why the "Controller" suffix is the default convention, as explained in Why do MVC controllers have to have the trailing 'Controller' convention on their class name?:
Imagine having a ProductController that likely handles Product application model entity instances. By not having the controller naming convention, we'd have two types with the same name hence would always have to provide namespaces to distinguish between the two.
To answer your questions:
Can we change this convention i.e. can I change setting somewhere and make suffix text 'MvcController' instead?
Yes, by building your own IControllerFactory. See Adding a controller factory to ASP MVC.
What is the reason C# compiler doesn't complain? It can not figure it out or it is not desired/illogical?
The naming convention is just an MVC construct. MVC is a framework that runs on top of .NET, nothing special about it.
The compiler can't figure this out, as there is no trivial way to expose runtime requirements that need to be checked at compile-time, like "If a class inherits from System.Web.Mvc.Controller or Microsoft.AspNet.Mvc.Controller, its name must end in 'Controller', unless there's a non-default ControllerFactory registered, in that case, use the conventions from that factory, whatever they are".
MVC relies on reflection to inspect types (and their names) at runtime. The C# compiler works at compile-time.
Unless you are under MVC 6, you need to name your controllers as follows
public class NameController:Controller{}
a controller must
be a public class
inherit from a controller or from a base class that inherits from controller class
not be abstract class
not be subclass
be named in a word ending in "Controller"
kinda new to MVC, and kinda new with Ninject. Playing around...
I've defined ninject in my MVC application as follows:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(
x => x.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces()
);
}
I have controller with a form and this ActionResult:
public ActionResult Index(IMember Member)
{
return View();
}
and it's returning an error: "Cannot create an instance of an interface."
Now I understand that it might not like the interface but isn't Ninject supposed to inject the real class in there? do I need to put in the actual class? if so, doesn't that take the point out of using interfaces and building a lossly-cuppuled apps?
BTW in my Index.cshtml file I have the following as the first line:
#model IMember
Thanks
You seem to be confusing constructor dependency injection with action method parameters, they are not the same thing.
In your case you seem to want Ninject to somehow inject a concrete IMember implementation whenever a client (browser, etc) calls the Index action.
Bear in mind that any parameters that are going to be passed into an Action method are going to be coming from the client and not from the framework, so it wouldn't make sense to do this.
I am sure there is a hack you could do to make it work for e.g decorate the parameter with [Inject] or something but you've already lost at that point because you have just "revealed your sources" to the controller which is against the point of Inverting control - you might as well just pass the Ninject IKernel to the controller.
Anyway in your case, Ninject will only inject into the Controller constructor (assuming you have correctly wired it up) and in that respect, Doug's answer here is actually correct - if that IMember is some kind of controller dependency, then you must inject it into the constructor, and store it in for e.g. a private member so that you can later refer to it from within action methods.
If the IMember is not a controller dependency but is instead just a model-bound parameter that you want passed to your controller, then Dependency Injection is not the answer - the parameter should be coming from the caller.
Also, there might be another problem even if you do end up using constructor injection.
The convention-based binding you are using requires that there is a single class called Member that implements IMember, i.e that the class name differs from the interface name only by lack of the initial "I". If this isn't the case for your class, then the convention-based binding will not work anyway and you need to use something explicit like
kernel.Bind<IMember>.To<MyMemberImplementationClassName>();
Hope that helps.
Is your RegisterServices method in the NinjectWebCommon.cs file located in the App_Start folder?
You'll also need to pass the Member object into the view kind of like below:
public class HomeController : Controller
{
private IMember _member;
public HomeController(IMember member)
{
_member = member;
}
public ActionResult Index()
{
return View(_member);
}
}
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.
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> {
}