0

Let' say I have this Declared Dictionary:

 private static Dictionary<int, List<Models.APIAccessControl>> _APIRights = GetAPIRights();

Where the key represents the roleId, the value represent the class:

 public class APIAccessControl
{
    public APIControllerRoute ControllerRoute { get; set; }
    public APIActionRoute ActionRoute { get; set; }
    public bool IsAuthorized { get; set; }

}

I am trying to check if the user is authorized to access this api. My idea is to query the dictionary and get all list of APIAccessControl for the roles, then query those APIAccessControl lists for the APIActionRoute he is trying to navigate:

I got the Dictionary Values that contain those list for the roles i want, but how to cast a List of Values to List and make this query:

public static bool CanAccess(int[] roleIDs, APIActionRoute apiActionRoute)
   {
            bool canAccess = false;

            var apiAccessList = _APIRights.Where(x => roleIDs.Contains(x.Key)).Select(x => new { x.Value}).ToList();

      //Querying to get all List<Models.APIAccessControl> that has any matchig   APIActionRoute
    }
3
  • You can try to extract the list using Values property of Dictionary. Commented Sep 29, 2016 at 15:59
  • can you provide sample code for doing the casting and query, i am trying to write it in elegant, clean way. So, if you have any thoughts please share your code. Thanks Commented Sep 29, 2016 at 16:01
  • You'll have to use a loop over apiAccessList to get all the ActionRoutes and add them in a list. There is alternative. The only thing that you can do is to use Linq. Let me know if that clarifies anything Commented Sep 29, 2016 at 16:14

4 Answers 4

1

You can modify the Select clause to give you the list you want:

var apiAccessList = _APIRights.Where(x => roleIDs.Contains(x.Key))
    .SelectMany(x => x.Value).ToList();

By not selecting to an anonymous class and by using the SelectMany, the list will be of type Models.APIAccessControl

Sign up to request clarification or add additional context in comments.

Comments

1

It would be better to iterate over the role ids first to take advantage of the Dictionaries lookup.

bool canAccess = false;
foreach(var roleId in roleIDs)
{
    List<Models.APIAccessControl> controls;
    if(_APIRights.TryGetValue(roleId, out controls))
    {
        canAccess = controls.Any(control => control.ActionRoute.Equals(apiActionRoute));
        if(canAccess)
            break;
    }
}

You'll have to make sure Equals actually does the type of comparison that you desire. By default it will be a reference equality, and you'd have to overload it inside of APIActionRoute if you want value equality, or use a comparison of the desired properties instead.

A completely Linq version is a little bit messy

List<Models.APIAccessControl> controls;
bool canAccess = roleIDs.Any(
    r => _APIRights.TryGetValue(r, out controls) 
          && controls.Any(
              control => control.ActionRoute.Equals(apiActionRoute)));

Comments

1

It sounds like you want SelectMany, which projects a "list of lists" into a single list:

var apiAccessList =
   _APIRights
   .Where(x => roleIDs.Contains(x.Key))
   .SelectMany(x => x.Value)
   .ToList();

You will then have every APIAccessControl object in one big list. It would no longer be grouped by roleID though. It might also have duplicates, which may or may not matter.

Comments

0

I think the SelectMany may help.

public static bool CanAccess(int[] roleIDs, APIActionRoute apiActionRoute)
{
    return _APIRights.Where(x => roleIDs.Contains(x.Key))
        .SelectMany(x => x.Value)
        .Any(a => a.ActionRoute == apiActionRoute);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.