Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Filter result in MVC 4 based on user

I have a custom authenticantion, when user logs in, I keep the necessary information on Session/Cache...

So, I have some Views with DropDowns that must show data filtered by User id... I´d like to known what the best way to filter that result...

1 - Direct on Controller?

...   
Model.MyList = repository.GetAll().Where(x => x.User.Id == userId);
return View(Model);

2 - Creating an action filter (How can I do that without querying unnecessary data from DB)

3 - Other way?

The problem with 1 is that I have several views that have the same dropdown, so I will have to repeat the same code.

like image 580
Paul Avatar asked Aug 05 '13 14:08

Paul


People also ask

When filters are executed in MVC?

Action filters are executed before or after an action is executed. The IActionFilter interface is used to create an Action Filter which provides two methods OnActionExecuting and OnActionExecuted which will be executed before or after an action is executed respectively.

What is filter and types of filter in MVC?

The ASP.NET MVC framework supports four different types of filters − Authorization Filters − Implements the IAuthorizationFilter attribute. Action Filters − Implements the IActionFilter attribute. Result Filters − Implements the IResultFilter attribute. Exception Filters − Implements the IExceptionFilter attribute.

What is filter in mvc5?

ASP.NET MVC Filter is a custom class where you can write custom logic to execute before or after an action method executes. Filters can be applied to an action method or controller in a declarative or programmatic way.


3 Answers

I would just create an action filter that puts the values you need inside a ViewBag and send it over to the view. This way you don't have to rewrite the same code over and over again and you can just concentrate on the view to display the data as necessary. Please see below for sample code:

using System.Web.Mvc;
namespace CustomActionFilter.CustomActionFilters
{
    public class MyResultFilterAttribute : FilterAttribute, IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext filterContext)
        {
            //The action filter logic - before 
            filterContext.Controller.ViewBag.userInfo = GetNeccUserInfo(filterContext.HttpContext.User.Identity.Name);
        }

        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            //The action filter logic - after
        }
    }
    private UserInfo GetNeccUserInfo(string userName)
    {
        using (var repo = new UserRepository(new UniteOfWorkUsers()))
        {
            var userInfo = repo.GetUserInfo(userName);
            return userInfo;
        }
    }
}

Hope this helps out :)

like image 26
hjavaher Avatar answered Oct 23 '22 23:10

hjavaher


Approach - 1

Function

private void userInfo(ResultExecutingContext filtercontext)
{                                        
    if (filtercontext.Controller.TempData[userId.ToString()] == null)
        filtercontext.Controller.ViewBag.userId =
            filtercontext.Controller.TempData[userId.ToString()] = 
            repository.GetAll().Where(x => x.Id == userId);

    else      //This will load the data from TempData. So, no need to 
              //hit DataBase.
        filtercontext.Controller.ViewBag.userId =
            filtercontext.Controller.TempData[userId.ToString()];

    TempData.Keep();  // This will save your Database hit.
}

Filter Method

public class MyActionFilter : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filtercontext)
    {
        //Call the Action Method before executing the View and after 
        //executing the Action.
        userInfo(filtercontext);
        base.OnResultExecuting(filtercontext);
    }
}

Controller Action Method

[MyActionFilter] 
//Whenever Action Method will execute. We will check TempData contains 
//Data or not.
public ActionResult Index()
{
    return View();
}

Key point about TempData and TempData.Keep()

  1. Items in TempData will only tagged for deletion after they have read.
  2. Items in TempData can be untagged by calling TempData.Keep(key).
  3. RedirectResult and RedirectToRouteResult always calls TempData.Keep() to retain items in TempData.

You could use Session Variable also, Only major problem is that Session Variable are very heavy comparing with TempData. Finally you are able to keep the data across Controllers/Area also.

TempData works in new Tabs/Windows also, like Session variable does.

Approach - 2

You can Cache the Data in some variable and can be reused again In the same manner done for TempData.

like image 118
Imad Alazani Avatar answered Oct 24 '22 00:10

Imad Alazani


This is a pretty default scenario that you want a user to see only data relevant to him.

Personally, I never did DB-Calls within the controller, I always had an additional DataLayer which I wired with an IoC-Container.

This DataLayer should only know the DataBase and how the data is stored, and filter this data correctly. You can argue if the DataLayer can use the HttpContext to automatically retrieve the user-ID or should get it as an argument.

So you not to have write always that expression you could also create a function, which will give you the correct Where-Lambda-Expression and you can simply use it:

public Expression<TModel> GetUserFilter<TModel>()
{
    var userId = GetUserId();
    var itemParameter = Expression.Parameter(typeof(TModel), "item");
    var whereExpression = Expression.Lambda<Func<TModel, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                "Id"
                ),
            Expression.Constant(userId)
            ),
        new[] { itemParameter }
        );
    return whereExpression;
}

And now you can call this function in you Controller or DataLayer:

Model.MyList = repository.GetAll().Where(GetUserFilter<Repository>());

You can of course change the names and make it shorter so that it's actually less to write :)

like image 1
peter Avatar answered Oct 24 '22 00:10

peter