Is it possible to find out which action class will be used to perform action with a given name?
Thank you
I assume you need this information at runtime. This will give you the action class name for the specified package and action name.
Dispatcher.getInstance()
.getConfigurationManager()
.getConfiguration()
.getPackageConfig("packageName")
.getActionConfigs()
.get("actionName")
.getClassName()
You can get the actual class too, if needed, along with lots of other information from the Configuration class.
Note: If you do not absolutely know the package and action name exists, then don't chain that call or you will probably get a NullPointerException.
If you are just looking for a sanity check during testing use the config-browser-plugin it will provide this information already on nicely formated pages: https://cwiki.apache.org/S2PLUGINS/config-browser-plugin.html
Related
I am developing an MVC application which makes use of plugins. I need to support using Web API from those plugins. I have it working (including Dependency Injection with Autofac as well). However, it seems like Attribute routing is completely ignored from the class libraries (plugins or any other assembly). For example, I have a test plugin specified as such:
[RoutePrefix("api/cms/test")]
public class TestController : ApiController
{
When browsing to /api/cms/test, I get the following error:
"No HTTP resource was found that matches the request URI '[my site]:30863/api/cms/test'.No type was found that matches the controller named 'cms'."
When I remove "cms", it works because it is then using the default route. Obviously this is not adequate, because I will very likely have multiple controllers with the same name (in different assemblies) and therefore need a unique route to each of them.
I inspected the Route Collection in System.Web.Http.GlobalConfiguration.Configuration.Routes as well to confirm and the route is indeed missing.
Is there anyone who can tell me why the attribute routes are being ignored for class libraries and if there's a workaround?
EDIT
Thanks to Kiran for the comment about the Route attribute; I did notice my error with forgetting the [Route("")] attribute on the controller which is to be used along with the [RoutePrefix] attribute. I added that and now attribute routing works fine. However, I still cannot have 2 controllers with the same name, even though they are in different assemblies. After doing some research it seems that this is a known issue - not just with different assemblies, but different namespaces in general. I tried to implement a solution from here:
http://shazwazza.com/post/multiple-webapi-controllers-with-the-same-name-but-different-namespaces/
The problem with this is that now the DataTokens is null AND read-only! So it is no longer a viable solution to this problem. Hoping someone else has a solution to this problem.
EDIT 2
Thanks to Kiran for his mention about route constraints. However, that still doesn't solve my problem. What I am looking for is a way to allow multiple controllers to have the same name whether they be in separate areas, separate namespaces or both.. whatever.. The problem with this is that the underlying Web API implementation looks up controllers by name using an IDictionary<string, HttpControllerDescriptor> variable to store such information. You can see this if you look at the source code for DefaultHttpControllerSelector. So, at first I thought maybe I just need to inherit this class and override GetControllerMapping() because the calling code in the internal class, AttributeRoutingMapper doesn't care about the keys in that dictionary at all... it only looks at the values. So at first I thought I could override this and use the full name of the controller (including namespace) as the key, so we can get them all in there. However, it is not that easy.. for a couple of reasons, not least of which is the fact that AttributeRoutingMapper is not the only class to call GetControllerMapping().
So it looks to be a lot of work to get what I need done; if is it even possible at all. I will be starting a bounty; 100 points to anyone who can provide a fully working solution or who can provide enough info for me to start a solution myself.
From the error message, looks like the order of routes are not correct...looks like your request is being matched by a conventional route (ex: api/{controller}) rather than the attribute route...as you know route order matters...so make sure to have attribute routes register before conventional routes as they are more specific...
Also note that RoutePrefix attribute alone doesn't add routes to the route table, but the attribute Route does...
I am guessing you are hosting your application in IIS?
I'm working on a Web API with MVC4, and I'd like to make it backwards-compatible, as I don't control when the clients are updated.
In order to do that, I'm going to create controllers on different namespaces, something like MyApp.Controllers.v1_0.AccountsController and MyApp.Controllers.v1_1.AccountsController
Obviously, when I create both of them and try to access to an action, I get "Multiple types were found that match the controller named 'Accounts'"
Then, what I tried to do is writing my own IHttpControllerActivator, so that when Create is invoked, it returns one of them... but that doesn't work b/c it never gets hit, which makes sense as Create receives an System.Web.Http.Controllers.HttpControllerDescriptor that includes information about the controller it's about to use.
Also, I can't just name the controllers different (Accounts1_0Controller, Accounts1_1Controller), as when the activators returns Accounts1_0Controller, it says that its name is not "Accounts"... it probably gets its name as Accounts1_0.
Do you see any way of either:
Set the namespace from the url? so that I have the url /v1_0/SomeAction or /v1_1/SomeAction and it searches the controller on the appropriate namespace
Having multiple controllers with the same MVC name but different class name?
Hope the issue is clear enough.
Thanks!
Fixed it implementing my own IHttpControllerSelector. It's great how Microsoft made MVC4 open source, made it almost painlessly looking at their System.Web.Http.Dispatcher.DefaultHttpControllerSelector.
I have a dropdown in my form that has a problem to populate when validation failed. I use xml validation with Preparable interface. To access data for dropdown I need to pass some ID from the form. The problem is when validation failed and prepare()/prepareInput() called, none of the variables in class including ID is set. ID is hidden parameter in the form that does not change. Please advice.
Thank you,
Yuri
prepare() in struts2 is rather synonymous with the role of init() in many other frameworks, that is it is called to initialise the action and fills a role very similar to the constructor.
There seems to be something missing... using the default-stack all the parameters on the action should have been set before validation is called. So if the client is indeed passing in the parameters I can not see why or how any would be missing unless some part of your logic clears them.
Sometimes it is necessary to acquire other objects as fields in your action derived from the values set by a form, or otherwise passed in as parameters. In this case you would like prepare to be called after values are set and then validate, if this scenario applies to you then the params-prepare-params stack is appropriate.
Personally, I would put preparation logic into the actions execute method rather than the prepare method. It is only when I put multiple actions into a single class that the prepare method is most appropriate as it factors out what would be repetition. Then the params-prepare-params is a special case that can crop up although I would argue the if you use DI it may never need to be used.
If this is not helpful please expand your question with the action class/xml mapping(if any) and provide the validation xml as well so we can see why this would be happening.
I am looking to have an attribute "show" on certain properties in my class and give the user the option to show other properties in the view.
Can I change a custom attribute from the front end?
Are you talking about the Filter attributes? If you are, you cannot change properties as they are statically defined, unless the code within the attribute happens to reference a static class or within the context at execution time, and then you pretty much can access within the attribute anything from that static or the context...
If I'm on the wrong track, please let me know.
HTH.
I am not sure attributes are the best approach for dynamically attaching metadata. Normally attributes are attached at code generation time.
Just wondering if there is a plugin out there that abstracts the process of deriving the instance of a current resource (or its class) from the current controller name?
Currently I just classify.constantize the controller name, and if that works then I test for the id paramater and load the record if it exists.
Yea, maybe it's a bit weird, but just wondered if someone's been there before and done it properly.
The reason it exists is because I need to know these objects to perform authentication on a granular level but I have about 35 different object classes so it needs to be abstract. I suppose I could assign #item to be the current item in each controller and rely on that but it seems a but unDRY.
inherited_resources :)
ResourceController by James Golick. It's out default in Blank, a starter application.