Is it possible, that Spring.Net Aspects don't work with Asp.Net Controller?
I want to configure transactions on Action methods of Controllers but the proxy doesn't seem to trigger.
<object id="ControllerClassPointcut" type="Spring.Aop.Support.SdkRegularExpressionMethodPointcut, Spring.Aop">
<property name="patterns">
<list>
<value>xxx.Controllers.CompanyController.*</value>
</list>
</property>
</object>
<aop:config>
<aop:advisor pointcut-ref="ControllerClassPointcut" advice-ref="TxAdvice"/>
<!-- TxAdvice taken from ServiceContext -->
</aop:config>
<tx:advice id="TxAdvice" transaction-manager="TransactionManager">
<tx:attributes>
<tx:method name="*" propagation="Required"/>
</tx:attributes>
</tx:advice>
and the action method of the CompanyController is:
[HttpPost]
public virtual ActionResult Create(Guid id, CompanyonViewModel vm)
{
...
}
but I the advice does not take effect although the pointcut is recognized. If I take an other class than a controller as pointcut it works.
for some methods the advice works. For example for the setter for the repository. But Sprint.Net does not recognize that the action method "Create" is called
Candidate is: 'xxx.Controllers.CompanyController.set_CompanyService'; pattern is 'xxx.Controllers.CompanyController.*'; matched=True
Candidate advisor [DefaultObjectFactoryPointcutAdvisor: pointcut [Spring.Aop.Support.SdkRegularExpressionMethodPointcut]; advice object = 'TxAdvice'] accepted for targetType [xxx.Controllers.CompanyController]
Thanks for your help
Can you try with the configuration
<aop:config proxy-target-type="true">
This will create an inheritance based proxy. you may need to download a recent nightly build of spirng.net for this to work (not 1.3.0).
I had a similar a problem with the [Transaction] attribute (which works using Spring.AOP).
In my case, I called the [Transaction] flagged methods from within the same class and was surprised that the transaction advice didn't fire.
The explanation was, that when calling a [Transaction] marked method from within the class, you hold a reference to the real instance instead of the AOP-proxied instance, therefore the call does not get intercepted.
When a request is made to an MVC app, then from the request url a controller is chosen (from the IControllerFactory instance). On this controller, the Execute method is called, which in turn is responsible for calling the actions. So I think that action methods are always called from within the controller. Which means that by definition action methods will never get intercepted. This would explain why those pointcuts are recognized, but don't fire.
if I take an other class than a
controller as pointcut it works
It also explains why pointcuts on other classes than controllers do fire: they are likely called from a controller, which will hold a AOP-proxied reference to instances of the other classes.
... for some methods the advice works ... For example for the setter for the
repository
I assume that your (for instance) CompanyController.CustomerController has a property CustomerRepository, set using DI. It makes sense that this pointcut fires, because the setter is called from outside the CompanyController.CustomerController, for instance by your DI container (or your ControllerFactory).
A solution could be to introduce service objects, on which you define the transaction advice that you now have on your controllers. From your controllers, you call methods on these service objects - and then the pointcuts will fire.
Related
As I can see, the action class in Struts 2 has multiple responsibilities.
First, we often put validation logic inside action class's validate method.
So when validation logic changes, we have to open class to modify.
Second, action class is responsible for making the result used by the JSP file. So when we intend to modify the view, we often have to modify action class and JSP together.
Third, action class has to know other classes' API to run the business logic and know how to handle the returned result.
At the end, the action class's code turns a mess.
Is there a better way to make the action class clean?
Or there's a book teaching how to write clean action class code?
The action class is a simple POJO. You can clean it as you like it only needs to implement Action interface.
The default entry method to the handler class is defined by the Action interface.
Action interface:
public interface Action {
public String execute() throws Exception;
}
First, we often put validation logic inside action class's validate method. So when validation logic changes, we have to open class to modify.
That's your choice, but I wouldn't. In general, validation logic should be handled via the XML configuration. If you have complex validation logic it should be isolated in its own handler then used as either a custom validator or called by a thin layer in validate.
An S2 action is the veneer between the web layer and the business logic–this includes validation.
Second, action class is responsible for making the result used by the jsp file. So when we intend to modify the view, we often have to modify action class and jsp together.
The action class may be used as the DTO between the business layer and the view layer, or you can use a separate entity and use the action to expose only that DTO. That's a necessity pretty much no matter what–again, the action acts as a thin layer between requests and responses. How you choose to organize it is up to you.
Third, action class has to know other classes' API to run the business logic and know how to handle the returned result.
Well yeah. Anything that sits between requests and business logic needs to know what to do. That said, it wouldn't have to, it could just transfer data from the request to the business logic. The mapping to the business logic doesn't need to be hard-coded at all.
At the end, the action class's code turns a mess.
That's your fault, not S2's.
Based on another question:
Creating a Child object in MVC4 - Parent's information not being passed to Create() controller
Does MVC provide a mechanism to send data from the HttpGet Create() to the HttpPost Create() without going through the client? If I need to send some data to the Post method that is meaningless to the client, how can I avoid cluttering the Views and over-exposing model properties to potential attackers?
Your GET and POST actions are just methods on a class. It really doesn't sound like there's any reason to use POST here, if your only concern is to execute a block of code under certain conditions.
Change your POST (drop the attribute) and make it a private method so it is inaccessible to the client. In your GET, do whatever checks you need to do, then invoke the method.
If you do need to expose the POST, refactor the code in question out to a seperate private method that you can call from either GET or POST. A better implementation would be a separate class with the method located there for reuse/testing/SoC.
Just a caution if you are working with a DB here...while there are some legitimate reasons to write to the DB during a GET, note that this is not the indempotent nature of the GET in most circumstances (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html).
Cheers.
Yes - as I mentioned in the other answer you can use TempData - however you don't need this. You are using nothing but an id and a name from your entity, just pass only those in the view model. You don't need the full entity.
On the server side ensure your user has access to those records. For example if I was editing a Customer record, I'd ensure the current user has access via something like:
var currentUsersCompanyId = GetCurrentUserCompanyId();
ctx.Customers.Single(o=>o.CustomerId = customerId and currentUsersCompanyId == customerId)
There are a variety of ways to do this based on how you control permissions - and third party platforms for .net such as Apprenda that help do this more automatically behind the scenes.
We have a series of ASP.NET MVC controllers that all inherit from a single base controller (that inherits from the Controller class). We are now looking at creating some asynchronous actions, and was wondering if we'd run into any trouble if we just changed the base controller to inherit from AsyncController instead of Controller (meaning all of our controllers would inherit from AsyncController).
Jess,
In my opinion, you'll do no harm as the asynch functionality is only called into play when you follow the conventions of:
public class PortalController : AsyncController
{
public void NewsAsync(string city)
{
AsyncManager.OutstandingOperations.Increment();
NewsService newsService = new NewsService();
newsService.GetHeadlinesCompleted += (sender, e) =>
{
AsyncManager.Parameters["headlines"] = e.Value;
AsyncManager.OutstandingOperations.Decrement();
};
newsService.GetHeadlinesAsync(city);
}
public ActionResult NewsCompleted(string[] headlines)
{
return View("News", new ViewStringModel
{
NewsHeadlines = headlines
});
}
}
the convention being the addition of the News*Async* and the News*Completed* portions in the naming.
see:
async controllers in asp.net mvc 2
Observe that the controller class now derives from AsyncController rather than Controller. In addition, the News action method has been split into methods named NewsAsync and NewsCompleted, which are analagous to the Begin and End methods in asynchronous pages. Logically, the controller still exposes a single action method named News. But physically, the method implementation has been broken up using a variation on the async pattern used throughout the .NET framework.
If you don't change anything in your inherited controller code, then no async activty will be initiated. However, as stated by Robert above (or below maybe :-)), you could decorate the actions on a needs must basis to keep the intention clear, tho', i personally think the convention should show that up clearly.
certainly worthy of debate.
MVC 4 doesn't have an asynch controller - see the source:
namespace System.Web.Mvc
{
// Controller now supports asynchronous operations.
// This class only exists
// a) for backwards compat for callers that derive from it,
// b) ActionMethodSelector can detect it to bind to ActionAsync/ActionCompleted patterns.
public abstract class AsyncController : Controller
{
}
}
See my tutorial Using Asynchronous Methods in ASP.NET MVC 4
If you set a breakpoint in your Action method and observe the callstack (with Show External code enabled), you will see that there are several additional steps required to invoke a synchronous action residing in an AsyncController vs. in a standard Controller. Namely the AsyncControllerActionInvoker invokes Begin/End style methods ending with BeginInvokeSynchronousActionMethod. I don't know how much overhead these extra calls contribute, but it is something to be aware of before you blindly extend all your controllers from AsyncController even where no Async actions exist.
You should be fine doing that since AsyncController already inherits from Controller.
See here for more information
The remarks on that page are quite useful for determining whether you're doing the right thing by inheriting from AsyncController and offers a nice guide to keep you on track.
The use of an Async Controller depends on whether you want to wait for any particular task or step to complete before going on to the next task. The problem is akin to buying something from Amazon before the money from your paycheck hits your checking account.
For typical web applications, I would say this is not advisable. The web server is already very parallel, so the only advantage would be speeding up responsiveness to the user. For many operations this benefit would be negligible.
I would reserve the Async Controllers for long-running processes in the background, where it is impractical to wait for the task to complete before returning the web page back to the user's control.
NOTE: If you have a copy of a .NET disassembler (or the ASP.NET MVC source), you can open up the AsyncController class and have a look at the code. That should give you a pretty good idea whether or not you can use the AsyncController as an ordinary Controller.
The article I linked to below says this: "Controllers that derive from AsyncController enable ASP.NET to process asynchronous requests, and they can still service synchronous action methods."
http://msdn.microsoft.com/en-us/library/ee728598.aspx
Is it possible in ASP.NET MVC via some extension/override points to allow a "delegate field" to be used as an "action"?
Something like:
using System;
using System.Web.Mvc;
namespace Company.Web.Controllers
{
public class SwitchboardController : BaseController
{
public Func<ActionResult> Index, Admin, Data, Reports;
public SwitchboardController()
{
// Generic views
Index = Admin = Data = Reports =
() => View();
}
}
}
I know I'm a little hell-bent for this one but if this is possible it'd open up many new ways of making actions. You could, for example, have Django-style generic views in MVC with only a single line of code to define the action or have different ways to factor duplicate logic across multiple controllers.
I'm not quiet sure where would be the place to slap this logic into or how much work would be required to alter something so fundamental in the framework.
You will probably have to build your own Controller factory. This class builds controllers, and implements IControllerFactory. You can inherit from DefaultControllerFactory. Override CreateController() to return your own IController.
Register your controller factory in Application_Start() of MvcApplication using this line:
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
In your implementation of IController, override the Execute method. You can use the RequestContext to decide which delegate to invoke. It would probably be easiest to inherit from ControllerBase, and override Execute in there if you don't want to fully implement IController.
The RequestContext passed into Execute carries a RouteData object. This is a dictionary populated by the routing engine that tells you what action should be invoked, and any parameters. You can get the action name like this:
//context is a RequestContext object passed to IController.Execute()
string actionName = requestContext.RouteData.Values["action"];
You could even define your action as a dictionary, and just pull them out once you get the action name.
One last thing, normal action methods return an ActionResult, which the framework uses to decide which view to render. Once you execute your delegates, I think you'll have to set some stuff manually in your special base controller. I'm not exactly sure what to set or how to get your View executed from here without cracking open the MVC source.
Good luck! This looks like an interesting idea.
As you seem to be implementing a BaseController in your code sample, if you override the Execute (from the IController) you'll be able to interpret the request => action however you like.
No, it isn't. The base controller is looking for methods and not for fields to dispatch an action.
EDIT:
Sorry, I was a bit fast and fixed to the standard classes provided.
You can do that but you have to overwrite the Execute Method in your controller or implement and provide your own IActionInvoker to dispatch the action to fields. Look into the post action processing in detail. It explains the dispatching in detail.
I have something similar to the following method:
public ActionResult Details(int id)
{
var viewData = new DetailsViewData
{
Booth = BoothRepository.Find(id),
Category = ItemType.HotBuy
};
return View(viewData);
}
and the following Route:
routes.MapRoute("shows","shows/{controller}/{action}/{id}", new {id = 0});
Everything worked fine before the Beta, when I had Preview 3. Now the method will fill the id correctly the first time I execute the action. However the second time the controller's ModelState contains the last-use id value. This causes the ActionInvoker to use it in the method's parameter instead of the Route value.
So if I call the action twice on two different entities the results are such:
www.mysite.com/shows/Booth/Details/1 => Details(1)
www.mysite.com/shows/Booth/Details/2 => Details(1) //from ModelState["id"]
From my quick scan with Reflector it seems it first binds parameters to the ModelState then to Routes. However, I never even posted anything from the model. As far as I can tell the ModelState should not contain anything.
Is this a bug in the Beta, possibly a bug somewhere in my code, or is there some design feature that I am ignorant of? Any insight into the nature of ModelState and why this happens is appreciated.
EDIT:
I discovered that this issue is actually a symptom of what appears to be a bug with the DefaultValueProvider if you instantiate a Controller from an IoC container that exists for the lifetime of the Asp.Net application.What happens is that the DefaultValueProvider uses the first ControllerContext given to the Controller and never updates it until the controller is recreated. This causes old RouteData to be used for method parameters instead of the current RouteData.
It's hard for me to tell what you expect to happen and what is happening from your post. Is it possible there's an error in your BoothRepository.Find method such that it returns the same thing every time?
ModelBinder should not be affecting this method because the parameter to the action method is a simple type, int.
Were both of these requests GET requests? If you still are having problems, can you try and create the simplest repro possible and email it to philha - microsoft dot com?
EDIT: The problem ended up being that the developer was attempting to re-use the valueprovider across requests (by having Castle Windsor manage the lifecycle of Controllers). Right now, there's no support for re-using controller instances across requests like you would with IHttpHandler which has a IsReusable property. So in general, reusing controllers across requests requires doing a lot more work on your end. :)
The problem is the LifeStyle, I completetly overlooked the fact it was being defined, which means by default the controllers will use the Singleton lifestyle. Setting the LifeStyle to Transient for all controllers will sort this problem.
if you use spring.net modify
Controller's singleton to "false"
This is a common issue when using Singleton behavior with a IoC container such as Spring.NET or Windsor. Controllers should not have singleton behavior because the ControllerContext is per request, much like HttpContext.