MVC获取/模拟存储库中的Windows用户

时间:2016-01-21 22:01:52

标签: asp.net-mvc dependency-injection asp.net-identity repository-pattern

我有一个使用Windows用户名的Intranet应用程序,并将其传递给过程以返回数据。

  1. 我正在使用依赖注入,但我不相信我有方法可以正确分隔用户名。
  2. 我试图通过不传递用户名作为参数来保持这种安全,但我也希望能够模仿(或绕过我的GetWindowsUser()方法)并发送另一个用户名,以便我可以测试结果其他用户。
    • 我对此有一个想法是在另一个页面中使用另一个(模拟的)用户名设置会话变量,然后在获取实际用户名之前先检查该会话变量是否存在,但我无法弄清楚如何访问存储库中的会话变量。
  3. WEB API控制器

    public class DropDownDataController : ApiController
    {
        private IDropDownDataRepository _dropDownDataRepository;        
    
        //Dependency Injection using Unity.WebAPI NuGet Package
        public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
        {
            _dropDownDataRepository = dropDownDataRepository;
        }
    
        [HttpGet]
        public HttpResponseMessage MyList()
        {
            try
            {
                return _dropDownDataRepository.MyList();
            }
            catch
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
            }
        }
    }
    

    存储

    public class DropDownDataRepository : IDropDownDataRepository, IDisposable
    {
        private DatabaseEntities db = new DatabaseEntities();
    
        public HttpResponseMessage MyList()
        {
            //(This should be separated somehow, right?) 
            //Create a new instance of the Utility class
            Utility utility = new Utility();
            //Grab the windowsUser from the method
            var windowsUser = utility.GetWindowsUser();
    
            //Pass windowsUser parameter to the procedure
            var sourceQuery = (from p in db.myProcedure(windowsUser)
                               select p).ToList();
    
            string result = JsonConvert.SerializeObject(sourceQuery);
            var response = new HttpResponseMessage();
            response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
    
            return response;            
        }
    }
    

    接口

    public interface IDropDownDataRepository : IDisposable
    {
        HttpResponseMessage MyList();        
    }
    

    UTILITY CLASS

    public class Utility
    {
        public string GetWindowsUser()
        {
            //Get the current windows user
            string windowsUser = HttpContext.Current.User.Identity.Name;        
    
            return windowsUser;
        }
    }
    

    更新1

    除了Nikolai和Brendt在下面发布的内容之外,还需要以下内容以允许Web Api控制器使用会话状态。 Accessing Session Using ASP.NET Web API

3 个答案:

答案 0 :(得分:1)

抽象Utility类并将其注入存储库。 然后你可以存根或模拟测试。

public interface IUtility
{
    string GetWindowsUser();
}

public class TestUtility : IUtility
{
    public string GetWindowsUser()
    {
        return "TestUser";
    }
}

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{

    private IUtility _utility;

    public DropDownDataRepository(IUtility utility)
    {
        _utility = utility;
    }

}

修改

此外,存储库不应返回HTTPResponseMessage类型,只返回您正在访问的域模型的List<T>

即。

public List<Model> MyList()
{
    //Grab the windowsUser from the method
    var windowsUser = _utility.GetWindowsUser();

    //Pass windowsUser parameter to the procedure
    var sourceQuery = (from p in db.myProcedure(windowsUser)
                       select p).ToList();

    return sourceQuery           
}

然后将JSON部分移动到控制器。

答案 1 :(得分:1)

  

我对此有一个想法是在另一个页面中设置会话变量   使用另一个(模拟的)用户名,然后检查该会话   在获取实际用户名之前,变量首先存在,但是我   无法弄清楚如何访问会话变量   库中。

潜在地,如果您向会话添加依赖项,则需要将其隔离,例如

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    // ... other fields

    private ISession session;

    public DropDownDataRepository(ISession session)
    {
        this.session = session;
    }

    public HttpResponseMessage MyList()
    {
         var myUserName = this.session.UserName;
         // ... etc

ISession就像:

 public interface ISession
 {
      string UserName { get; }
 }

实施为:

 public class MySession : ISession
 {
     public string UserName
     {
         get
         {
            // potentially do some validation and return a sensible default if not present in session
            return HttpContext.Current.Session["UserName"].ToString();
         }
     }

 }

如果需要,当然有可能将此MySession课程与HttpContext分开。

对此:

    //(This should be separated somehow, right?) 
    //Create a new instance of the Utility class
    Utility utility = new Utility();

是的,无论何时创建new对象,您都将它们紧密地耦合在一起,这会给您带来问题,例如,如果您尝试单独对其进行单元测试。

在这种情况下,您可以从IUtility提取Utility界面:

public class Utility : IUtility
{
    string GetWindowsUser();
}

然后:

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    // ... other fields

    private IUtility utility;

    public DropDownDataRepository(IUtility utility)
    {
        this.utility = utility;
        // .... etc

然后你删除了UtilityDropDownDataRepository之间的依赖关系,可以轻松替换其他类型或模拟。

答案 2 :(得分:0)

我从尼古拉和布伦特那里得到了很多帮助,并且通过他们发布的答案获得了大部分帮助,但最终我自己找到了完整的答案。我遇到的问题与无法访问WebAPI中的会话变量有关。所以,我确信有更清洁的解决方案,但我肯定改进了我所拥有的,并提出了以下代码,这是有效的。

需要这个答案才能访问Web Api中的会话变量 - Accessing Session Using ASP.NET Web API

<强>的global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        UnityConfig.RegisterComponents();
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    //Added to allow use of session state in Web API
    protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

    //Added to allow use of session state in Web API
    private bool IsWebApiRequest()
    {
        return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
    }

    protected void Session_Start(Object sender, EventArgs e)
    {
        //Default set the session variable to none
        Session["_impersonatedUser"] = "none";
    }

    protected void Session_End(Object sender, EventArgs e)
    {
        //Reset the session variable to blank
        Session["_impersonatedUser"] = "";
    }
}

<强> UNITY.config

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();


        container.RegisterType<IDropDownDataRepository, DropDownDataRepository>();
        container.RegisterType<IUtilityRepository, UtilityRepository>();
        container.RegisterType<ISessionRepository, SessionRepository>();

        //MVC5
        //Unity.MVC5 NuGet Package
        DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

        //WEB API 
        //Unity.WebApi NuGet Package
        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
    }
}

WEB API控制器

public class DropDownDataController : ApiController
{
    private IDropDownDataRepository _dropDownDataRepository;      

    //Dependency Injection using Unity.WebAPI NuGet Package
    public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
    {
        _dropDownDataRepository = dropDownDataRepository;
    }

    [HttpGet]
    public HttpResponseMessage MyList()
    {
        try
        {
            var sourceQuery = _dropDownDataRepository.MyList();

            //JSON stuff moved to controller
            string result = JsonConvert.SerializeObject(sourceQuery);
            var response = new HttpResponseMessage();
            response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");

            return response;
        }
        catch
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
        }
    }

    protected override void Dispose(bool disposing)
    {
        _dropDownDataRepository.Dispose();
        base.Dispose(disposing);
    }
}

DROPDOWNDATA REPOSITORY

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    private DatabaseEntities db = new DatabaseEntities();
    private IUtilityRepository _utilityRepository;
    private ISessionRepository _sessionRepository;

    //Dependency Injection of Utility and Session
    public DropDownDataRepository(IUtilityRepository utilityRepository, ISessionRepository sessionRepository)
    {
        _utilityRepository = utilityRepository;
        _sessionRepository = sessionRepository;
    }

    //Changed to a list here
    public List<MyProcedure> MyList()
    {
        string windowsUser;
        //Check the session variable to see if a user is being impersonated
        string impersonatedUser = _sessionRepository.ImpersonatedUser;

        //Grab the windowsUser from the Utility Repository
        windowsUser = _utilityRepository.GetWindowsUser();

        if (impersonatedUser != "none")
        {
            windowsUser = impersonatedUser;
        }        

        //Pass windowsUser parameter to the procedure
        var sourceQuery = (from p in db.MyProcedure(windowsUser)
                           select p).ToList();

        return sourceQuery;            
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                db.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

DROPDOWNDATA INTERFACE

public interface IDropDownDataRepository : IDisposable
{
    //Changed to list here
    List<MyProcedure> MyList();
}

UTILITY REPOSITORY

public class UtilityRepository : IUtilityRepository
{
    public string GetWindowsUser()
    {
        //Get the current windows user
        string windowsUser = HttpContext.Current.User.Identity.Name;

        return windowsUser;
    }
}

实用程序界面

public interface IUtilityRepository
{
    string GetWindowsUser();
}

会话存储

 public class SessionRepository : ISessionRepository
{
    public string ImpersonatedUser
    {
        get
        {
            return HttpContext.Current.Session["_impersonatedUser"].ToString();
        }
    }
}

会话界面

public interface ISessionRepository
{
    string ImpersonatedUser { get; }
}