views:

349

answers:

3

I have a transaction attribute that performs a commit in the onactionexecuted method.

This is specified at the controller method, for one of my actions i need to override that method and not call the code in onactionexecuted?

Here is some sample code.

[Transaction]
public class TestController
{
    public ActionResult Index()
    {
        return View();
    }

    [NoTransaction]
    public ActionResult Test()
    {
        return View();
    }
}

The [NoTransaction] attribute should override the onactionexecuted method in [Transaction]. Is there a way to do this?

A: 

In the NoTransaction attribute's OnActionExecuting you could put some sort of a flag in HttpContext.Items which you can then check for in the Transaction attribute's OnActionExecuted. Or some variation on that.

HTHs,
Charles

Charlino
Does the [NoTransaction] run first?
Schotime
I think the order will be:`Transaction.OnActionExecuting` -> `NoTransaction.OnActionExecuting` -> `NoTransaction.OnActionExecuted` -> `Transaction.OnActionExecuted`
Charlino
+4  A: 

All action filters have an order property. If it's not defined, it has an implicit value of -1. When filters have the same order, the order is determined by scope: is it applied to a controller or applied to an action.

Controller scoped filters of the same order run before action filters of the same order.

The simple workaround is to apply an explicit ordering in this case to the Transaction attribute.

[Transaction(Order=1)]
public class TestController
{
    public ActionResult Index()
    {
        return View();
    }

    [NoTransaction(Order=0)]
    public ActionResult Test()
    {
        return View();
    }
}

This will ensure that NoTransaction runs before Transaction does.

If you want NoTransaction to override Transaction, the simplest thing to do is to have NoTransaction add some special key in HttpContext.Items which the Transaction attribute reads. The presence of this key would tell the Transaction attribute to not do anything.

Haacked
+2  A: 

If your NoTransactionAttribute is a filter, you can set a flag within its OnActionExecuting() as suggested in the other post. Otherwise:

// just a marker attribute with no special logic
public sealed class NoTransactionAttribute : Attribute { }

public class TransactionAttribute : ActionFilterAttribute {
    public override void OnActionExecuted(ActionExecutedContext filterContext) {
        if (filterContext.ActionDescriptor.IsDefined(typeof(NoTransactionAttribute), true /* inherit */)
            || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(NoTransactionAttribute), true /* inherit */) {
                return; // should skip logic
        }

        // perform your logic here
    }
}
Levi