Share via


Exercise 2: Creating a Global Dynamic Filter

In this exercise, you will learn how to create a global dynamic filter that will get executed or not depending on the context. This means that you could set any filter as global, but use it only for the controllers or actions that satisfy a certain condition. For that purpose you will implement GetFilters method in your custom filter provider to add your own logic behind the filter retrieval.

Task 1 – Creating a Filter Provider

In this task, you learn how custom Filter Providers manage the global behavior of any MVC Filter. You will create a custom Filter Provider that stores the controller actions to log and applies the filter when an action is in the list.

  1. Open Begin solution from \Ex02 – Global Dynamic Filter\Begin.
  2. Create a new class in Filters folder and rename it ActionLogFilterProvider.[cs|vb].
  3. Add the reference to the System.Web.Mvc namespace.

    C#

    using System;
    FakePre-1ce31514268b416da1d414a21759e4ec-e2d6227877c34d789097a95489fbfdcfFakePre-ea7dddc31da74d4995259502201428bb-3405e8cf3d87488e99edd81c04bc9759FakePre-f99fe00e99414b6c8ea343eeb16c1189-9d512dd3f70f433fb5f4da65022fc91eusing System.Web.Mvc;FakePre-22e9a3a6ee924ba0b9cd52948e7bfeb0-b41fb4ba21934ac3ba6637b60dc4eb01FakePre-4d8c5bf0587940ef9df08eb840d7c371-8fd223cf2caa4e5082d1adacd2bf3030FakePre-e047ea007f2a48649ea6bb35c571ac0e-bcf25f5c21b74f62ab4207d7f4ff3768FakePre-6b444362b4c948fd9ef39120c83f82e0-1190e567bc0f4053824e8332ba03ac26FakePre-a231679d939d4537ab2594a15109d2c6-131cae3ede3a4e219950b00129b934c3FakePre-5c4372ee2e3442aea72625bb2d0d5647-29db2545317c4e1292dbca4681ce50a0FakePre-0970d65f97564cb5b685165f9bcff96f-04ceaf199e734ad49a9a72693920475c

    Visual Basic

    Imports System
    FakePre-5f7e55cca8a244da986897107ddb2f94-7ee4e7f2d1594932a119eb115261ca3bFakePre-11859528887444649da52c04df1368d8-28bf5808b7e14b119746e84ec60a2254FakePre-e3781021f03841608d90679aeb5fa4d8-97a55ae4bed341389ed8530c41b481f8Imports System.Web.MvcFakePre-d37d088bbbeb4bffa4a803d0638de9cd-3cbfe0c9687d4fa5b0501cecb39857d3FakePre-dc9d705251fc463b87f8843341a16125-1619bbabe55f4aa084711b2b7e068326FakePre-0d1f4cffa7984c29a26caf3e0aeff430-4a073b2cee844f0ea1080f1ba8032b8bFakePre-9da987e762404baba4196133c50d84dc-cad0a3b4e7344e7b85d39b1d1028524c

Make ActionLogFilterProvider implement the interface IFilterProvider.

C#

public class ActionLogFilterProvider : IFilterProvider

Visual Basic

Public Class ActionLogFilterProvider Implements IFilterProvider

  1. Define the internal class ControllerAction inmediatly after ActionLogFilterProvider class definition that will have a controller and action names as the members.

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 ControllerAction – CSharp)

    C#

    using System;
    FakePre-ada2a2ffe48841b8b0e50556e596fabe-fbfeb167b0fe45d4bfaf8e156b246c72FakePre-5437d16ba7714e3cac5f32bcfc72ab3b-94f7f7563aa84e63b58d8a1991cc9855FakePre-e11bbe8f9d874c85ada9b508e760e4fc-c0309e046b264265b99ab6bae0ba3c46FakePre-251a2b379e95414b969fc642b621c82d-0f2da804060f4acf829b5039ce12e8c3FakePre-7557cf1ca7514933b041814d493a8b6a-293f1161cb3644008ce73ae20fc4c62bFakePre-62e316004bd045a0a6b4354382e19396-ff487fb7ca7a41deaade05b9e64a98b9FakePre-30f7727993b74d63a41fb5cb2fea9bb4-a7360c33df0c440aae7d0fcca83ca968FakePre-263ccf909cf74dd8bb63ad1dc7b8bc6c-9c28f78516e84461b448558e51020ec8FakePre-7670c12d350544d78e6e856f7c5d64ee-bc3cf0102337498e8ddbc4836d70b3d6FakePre-2df334243bc74035b11d09d9da1c2cd0-0e549557571a415a9b0c4ac8eae041d2FakePre-d9e48ad1315c4ff79e6b3832c8c49f2a-72ebfca698904c8d99fad9aa1279c6ce internal class ControllerAction { internal string ControllerName { get; set; } internal string ActionName { get; set; } }FakePre-ba14dff1ee90451594348a3b79efe4b8-8263521147444edc8500cedf2d48f816

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 ControllerAction – VB)

    Visual Basic

    Imports System
    FakePre-eef4a6432f97497bbbf8685e0c9f4672-a44dab47d3fb4321bf7b10a2b2035f4dFakePre-f14444c1aeff46aca439e22ac349736d-6e7b65cce8a143729fb42e1c04500447FakePre-d9e9ee2250bb452d8ac64da14ff998f2-4836e7c6fec5451598e8f130c790c9b7FakePre-5ae93e342f204e12872d70dc07516670-2f1d8cadfbe14d5387e2be480bd36a1aFakePre-6484e66b4ce243ee86bdaab71ddb9e37-7a8b20124fd9485c810a9a0ef6e46cddFakePre-d25da081f8a2490db24a90eb289338ad-dd2435889b7140e1a39964e4c38eaf65FakePre-dc34cf2094ef4a31885ef0e3d3e93bfa-2fd0c408040d45a881cf8228f01c0d45FakePre-0afa6d1387004a0fba085950cfc93554-184d6b3bc13340af836f858969c2371fFakePre-ff6ed13f6ceb4e4782ffd42705a7800c-713faa9f2de748d4aa24139a10aa7cefFriend Class ControllerAction Friend Property ControllerName As String Friend Property ActionName As String End Class

  2. Then define a list of ControllerAction elements as new ActionLogFilter property:

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 Actions List – CSharp)

    C#

    FakePre-dbdaed82112d449daafba423234e5c2b-9973aed128bc4c5f9b7202753e299da6FakePre-798611e6d63e48fe9503bddf3d28ef14-97bc77b527e34e9086e5fcad77077263FakePre-2c2268fe3e6d432c9e42dc23cfb3e87c-13c8564634cd4f97b7de13f7b94ff3afFakePre-36714fe93d6342fd9322bbd45e55cb62-39018920d6ec423ea473134f800b5e74FakePre-34dc5e775c7b42238e09ef22ba52c303-8dcbaee7145244b6ac56352c62df1593FakePre-1e313b3882134035840d3dcdcfc8b5db-a6c33af18eb24c83b06d78f1e1f98cc6FakePre-aa85f4e9d68942f19002b25b4ae116d0-1be3a5fa330c4fde83ba8b994d36cc01FakePre-374b022f32e5453fbb3ee5f685c8a9e3-602eb4081a8c40708b85e0ba505fe692FakePre-3053bb20f667477fbd4ea7d7d69c4ced-a36d6d22c38b48c6a3f524440e92de5eFakePre-06e55727143745c499f299f719f64ca2-00b00250e5f841acb5558618d7d8c87c private IList<ControllerAction> actions = new List<ControllerAction>();FakePre-80c6f1a760214accba1541c63b66350f-07643539c985446b8cf8ffed62d16772FakePre-8e549996d7cc4c498f8f389978845f92-96b1212faa4e4795876c98f74901cf47FakePre-049b05a8d06b48ec99ed89d9bf03b2e9-e1b1847a27fa434bb9387045930306d5FakePre-cef940b164cc4ba98d54ea4f63c78d0f-2f4d561c1bdb45768879f088f25d90b5FakePre-f5ad527e5c044b16bd41b2f549914562-809a30087e6c4e47bdf9ef6fbb1603b0FakePre-4d9cd5d4bb9a4451b0e071f055927c31-bd42dd9cd31546a2aa13212d25dbeb41FakePre-9031269702634f66aa71e64341b7de18-892b6c3fe9cc4e6bb8d6b6f34e2d88d5FakePre-43be4c998e0144e998ca522114855eee-dc829182a1fe4f689e5bddfe95aa7535
    

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 Actions List – CSharp)

    Visual Basic

    Imports System
    FakePre-5b82a261a2a04c8cbc3089169627a0a9-ea4497bf71a04508a9e631a632addb6dFakePre-bdaa71e01e254fabbd52e927e8928980-a0ed9a03cbfc4487a0e33fbc0c4e29e0FakePre-dd0f8881195e439ba75b3833142f9ab1-6d52d8f016ce498bb4802077578ee2ddFakePre-d8cbfd162e4749b6b4c855a7cfbed985-6b84bd9500f048e3adf0f5e2170bf47cFakePre-f4e58c0d68eb49999be67db148d44f33-9c0b03989e5747b78ebc0f12e888e6deFakePre-449161b59e61454b9da27cdc8fc06a9b-a0d9f1adc6854f8b914b1b2c64181cd7 Private actions As IList(Of ControllerAction) = New List(Of ControllerAction) FakePre-e2e1f0ab35464c828df2fb2e9bb82876-cc2d80c72aa24c5e9d7d0973c78d2d69FakePre-c267d7acb86c44f8bd6866148d556658-0ba43a9e780b4bb8b5086b3c3cd140d3FakePre-55350b4a4f064affb5acf7f3d546b66a-6649e14191e24fce9a029027521f91a6FakePre-4f8e1e7cf4504ed6b0a8472f14fcbdc2-237ca02631b34e2d9fabe641f6de1b28FakePre-f5a82c37b5794164ad3955b8c2409396-130684567fda4cdeb858b6c37907653aFakePre-59f26aa62a8149b4ab3b71c9bba40ea7-ac702c4c952847129b11d461bb83b84d

  3. Create an Add method to ActionLogFilterProvider class to store in the list all the controllers and actions that will be logged:

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 Add Method – CSharp)

    C#

    FakePre-503e3cbda3ad4763bbd762231a417b1d-7f318fcd37fe47cb8bf969a9a66b74d9FakePre-8f918a658292423ab6b9e9ce1e9df541-018334e80bb24d889b98eb513cbfa1a6public void Add(string controllername, string actionname) { actions.Add(new ControllerAction() { ControllerName = controllername, ActionName = actionname }); }FakePre-b8e6495e2a844cf3b9769762b0b303c1-3abbbf255f71415784aedfdb2568d933

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 Add Method – VB)

    Visual Basic

    FakePre-63a27004464e4703aa718ea49a036377-d6eaac7a2f9342529ae8e39faf63fc3cFakePre-a80128f5acfd42c399764368f8b86421-e7974cf0c1df4354bc2a59fdf182ff98Public Sub Add(ByVal controllername As String, ByVal actionname As String) actions.Add(New ControllerAction With {.ControllerName = controllername, .ActionName = actionname}) End SubFakePre-5e9c64e78a4346bd9da7482dbaf069e8-05b8ec818e2546329426c747be6e8d03

  4. Implement in ActionLogFilterProvider class the method GetFilters that will read the list of controller actions and evaluate which ones apply to the filter.

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 GetFilters – CSharp)

    C#

    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { foreach (ControllerAction action in actions) if ((action.ControllerName == actionDescriptor.ControllerDescriptor.ControllerName || action.ControllerName == "*") && (action.ActionName == actionDescriptor.ActionName || action.ActionName == "*")) { yield return new Filter(new ActionLogFilterAttribute(), FilterScope.First, null); break; } yield break; }FakePre-83918575eab242dbb92cbe1f28b6e056-5c49205864264282ac42e077e7eda93a

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 GetFilters – VB)

    Visual Basic

    Public Function GetFilters(ByVal controllerContext As ControllerContext, ByVal actionDescriptor As ActionDescriptor ) As IEnumerable(Of Filter) Implements IFilterProvider.GetFilters Dim result = New List(Of Filter) For Each action As ControllerAction In actions If (action.ControllerName = actionDescriptor.ControllerDescriptor.ControllerName OrElse action.ControllerName = "*") AndAlso (action.ActionName = actionDescriptor.ActionName OrElse action.ActionName = "*") ThenFakePre-7a972fb78f5f4ca591fbcf10bfe961e6-ced9e1c5aef54a5da4fa5dc19d2b1c94

    result.Add(New Filter(New ActionLogFilterAttribute, FilterScope.First, Nothing)) Return result Exit For End If Next action Return result End Function

    Note:
     This implementation of GetFilters method checks if the controller name and the action name are in the list and returns a new instance of the custom action filter class ActionLogFilterAttribute. You could also use the Controller Context parameter to add more complex logic to this method.

    The "*" will be used as a wildcard for not filtering by a controller name or an action name. You can find ControllerContext class reference in this article at msdn.

  5. Your filter provider class should finally look like this:

    C#

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcMusicStore.Filters { public class ActionLogFilterProvider : IFilterProvider { private IList<ControllerAction> actions = new List<ControllerAction>(); public void Add(string controllername, string actionname) { actions.Add(new ControllerAction() { ControllerName = controllername, ActionName = actionname }); } public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { foreach (ControllerAction action in actions) if ((action.ControllerName == actionDescriptor.ControllerDescriptor.ControllerName || action.ControllerName == "*") && (action.ActionName == actionDescriptor.ActionName || action.ActionName == "*")) { yield return new Filter(new ActionLogFilterAttribute(), FilterScope.First, null); break; } yield break; } } internal class ControllerAction { internal string ControllerName { get; set; } internal string ActionName { get; set; } } }

    Visual Basic

    Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Web Imports System.Web.Mvc Public Class ActionLogFilterProvider Implements IFilterProvider Private actions As IList(Of ControllerAction) = New List(Of ControllerAction) Public Sub Add(ByVal controllername As String, ByVal actionname As String) actions.Add(New ControllerAction With {.ControllerName = controllername, .ActionName = actionname}) End Sub Public Function GetFilters(ByVal controllerContext As ControllerContext, ByVal actionDescriptor As ActionDescriptor ) As IEnumerable(Of Filter) Implements IFilterProvider.GetFilters Dim result = New List(Of Filter) For Each action As ControllerAction In actions If (action.ControllerName = actionDescriptor.ControllerDescriptor.ControllerName OrElse action.ControllerName = "*") AndAlso (action.ActionName = actionDescriptor.ActionName OrElse action.ActionName = "*") Then result.Add(New Filter(New ActionLogFilterAttribute, FilterScope.First, Nothing)) Return result Exit For End If Next action Return result End Function End Class Friend Class ControllerAction Friend Property ControllerName As String Friend Property ActionName As String End Class

    In the following step you will add this provider to the global filter provider collection.

Task 2 – Registering a Global Filter

In this task, you will register a custom filter provider as global in the Global.asax.[cs|vb].

  1. Add an instance of your filter provider into MVC FilterProvider collection, in the method RegisterGlobalFilters at Global.asax.[cs|vb] class:

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 LogProviders – CSharp)

    C#

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    FakePre-21b4f07c4b584bcda6e85def8f00fe5c-b8e1845f06d04a239877beaa040efc4aFakePre-f19c016ed5904ddd84ff54b3c2beab00-fed7797aab324b168bce38d0bc28b307 ActionLogFilterProvider provider = new ActionLogFilterProvider(); provider.Add("Account", "LogOn"); provider.Add("Store", "*"); provider.Add("*", "Index"); FilterProviders.Providers.Add(provider);FakePre-031b0850d0dd469fb4c56244a2985fd2-cb8729d73c1049a6b9ab08e88f60d45a

    (Code Snippet – ASP.NET Global and Dynamic Action Filters – Ex2 LogProviders – VB)

    Visual Basic

    Public Shared Sub RegisterGlobalFilters(ByVal filters As GlobalFilterCollection)
    FakePre-d3159979fafa4911a792c91954ba31b2-e1294c38d3a6438bb1b18bf23565618dFakePre-f718e2382bf2431a9ff772f6082e0189-6ae7079bae2841388465e2b0a1f92d14 Dim provider As New ActionLogFilterProvider provider.Add("Account", "LogOn") provider.Add("Store", "*") provider.Add("*", "Index") FilterProviders.Providers.Add(provider) FakePre-5ae611f03b9e47bd8ca85b2f6bfe13f3-7b909dd24eeb4a9f9b0e42021e952625

    Note:
    ActionLogFilterProvider Add method receives the controller name and the action name parameters of the elements that will perform logging. In this solution the elements are:

    1. “Account” ,“LogOn”: By sending the controller and the view you add logging to a specific functionality

    2. “Store”, “*”: Using the wildcard “*” at action name, All the actions from “Store” are logged

    3. “*”, “index”: Using the wildcard “*” at controller name, All actions “index” at any controller are logged

Task 3 – Running the Application

In this task, you will check that the controllers added to the filter provider list are actually performing the log.

  1. Press F5 to run the application.
  2. Browse to /ActionLog to see the initial status of the log:

    Figure 3

    ActionLogView Initial state

  3. Browse /StoreManager to see the LogOn view, which is selected for the log filter.
  4. Browse /Account/Register view, which is not selected for the log filter.
  5. Browse /ActionLog and press F5 to see the logged information:

    Figure 4

    ActionLogView: logged activity only for the selected views

Next Step

Summary