How to access DbContext from outside of the Controller? - asp.net

I have class UserFactory where I want to check if User already exist in database, if not it will be automatically created. But having difficulties with accessing DbContext from outside the Controller.
public UserFactory(DbContextOptionsBuilder builder)
{
_dbContext = new PMSContext(builder.Options) ;
}
public User Create(WindowsIdentity currentWindowsUser)
{
User user = new User();
string name = currentWindowsUser.Name.Replace("DOMAIN\\", "");
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal ADuser = UserPrincipal.FindByIdentity(ctx, name);
if(ADuser != null)
{
User userInDatabase = _dbContext.Users.Where(u => u.SamAccountName == name).FirstOrDefault();
}
}
And than in the Startup.cs I habe :
public Startup(IHostingEnvironment env)
{
var builder = new DbContextOptionsBuilder<PMSContext>()
.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
User user = new UserFactory(builder).Create(WindowsIdentity.GetCurrent());
}
But I'm getting error:
Severity Code Description Project File Line
Error CS1503 Argument 1: cannot convert from 'Microsoft.Data.Entity.Infrastructure.SqlServerDbContextOptionsBuilder' to 'Microsoft.Data.Entity.DbContextOptionsBuilder'
Is this the right way to access DbContext from the outside of the Controller?

The answer was quite simple:
var optionsBuilder = new DbContextOptionsBuilder();
optionsBuilder.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
var context = new PMSContext(optionsBuilder.Options);
User user = new UserFactory(context).Create(WindowsIdentity.GetCurrent());

Related

ASP.NET MVC 5 Page Controlled by Active Directory Group

Is it possible to create a page (View) that is strictly controlled by an Active Directory Group?
There is no login for this page, if you are a member of the "VIP" Active Directory group, then the page is rendered, otherwise if not then you can't see it.
First get your current users windows log in
var windowsUserName= HttpContext.Current.User.Identity.WindowsLogin();
Then get all the AD groups for your user using the System.DirectoryServices
using System.DirectoryServices;
public List<string> GetUsersActiveDirectoryGroups(string windowsUserName)
{
try
{
var allUserGroups = new List<string>();
if (windowsUserName == null) return allUserGroups;
var domainConnection = new DirectoryEntry();
var samSearcher = new DirectorySearcher
{
SearchRoot = domainConnection,
Filter = "(samAccountName=" + windowsUserName + ")"
};
samSearcher.PropertiesToLoad.Add("displayName");
var samResult = samSearcher.FindOne();
if (samResult == null) return allUserGroups;
var theUser = samResult.GetDirectoryEntry();
theUser.RefreshCache(new[] { "tokenGroups" });
_bet365EmployeeFullName = theUser.Properties["CN"].Value.ToString();
foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])
{
var mySid = new SecurityIdentifier(resultBytes, 0);
var sidSearcher = new DirectorySearcher
{
SearchRoot = domainConnection,
Filter = "(objectSid=" + mySid.Value + ")"
};
sidSearcher.PropertiesToLoad.Add("name");
var sidResult = sidSearcher.FindOne();
if (sidResult != null)
{
allUserGroups.Add((string)sidResult.Properties["name"][0]);
}
}
return allUserGroups;
}
You now need to map which groups have access to which view in the application.
Once done, the next step is the restricting of the viewing of "Views".
You need to set up a permissions filter that uses the MVC AuthorizeAttribute. Something like the below.
public class PermissionsFilter : AuthorizeAttribute
{
private readonly string _viewName;
public PermissionsFilter(string viewName)
{
_viewName = viewName;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
//Check to see if users groups has access to the view
//If not redirect to unauthorized page
}
}
I accomplish the above by have a user object held in session. This contains a list of all the application permissions my user has access too. This is the mapping you need to do. I have all my view names stored in the database along with an ID of which AD groups can access them.
Then finally in the controller, decorate the get action for the view accordingly.
[HttpGet]
[PermissionsFilter("ViewName")]
public ActionResult ReturnMyView(int currentFolderID)
{
return View(); //Etc..
}
Well hope that helps!

InitializeIdentityForEF freezes and does not create the default admin account

When I first started the project, I had no errors.
Now, when I run the project and it creates the database, it keeps loading and loading. If I stop and run again, everything works fine, except my admin account was not created.
I'm using Identity 2.0.
Here is the code:
public static void InitializeIdentityForEF(ApplicationDbContext db) {
var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
const string name = "admin#mundogato.org";
const string password = "Admin#1234";
const string roleName = "Admin";
//Create Role Admin if it does not exist
var role = roleManager.FindByName(roleName);
if (role == null) {
role = new ApplicationRole(roleName);
var roleresult = roleManager.Create(role);
}
var user = userManager.FindByName(name);
if (user == null) {
user = new ApplicationUser { UserName = name, Email = name };
var result = userManager.Create(user, password);
result = userManager.SetLockoutEnabled(user.Id, false);
}
// Add user admin to Role Admin if not already added
var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name)) {
var result = userManager.AddToRole(user.Id, role.Name);
}
}
Had the same issue where OWIN wasn't ready at that point. Try this code for the managers, assuming ApplicationDbContext derives from the Identity Context:
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(db));
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
See Understanding MVC-5 Identity

EF - Seed function not updating table

In asp.net webform application, trying to save user to AspNetUsers after UPDATE-DATABASE command. the following code doesnt do that. solution ?
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(MyApp.Models.ApplicationDbContext context)
{
if (!context.Users.Any(u => u.Email == "some#mail"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { Email = "some#mail" };
manager.Create(user, "password");
}
}
In order to add ApplicationUser you must have the property Username initialized.

Faking Http Context with Moq and Mvc

I’m trying to fake http context to test a Controller. My environment is MVC 3 and Moq 4.
So far I have tried a few options including:
a.
var searchController = new MySearchController(_mockResolver.Object.Resolve<IConfiguration>());
var mockContext = new Mock<ControllerContext>();
searchController.ControllerContext = mockContext.Object;
var result = searchController.Render();
b.
var searchController = new MopSearchController(_mockResolver.Object.Resolve<IConfiguration>());
searchController.MockControllerContext();
var result = searchController.Render();
public static class MockHttpHelper
{
public static Mock<HttpContextBase> MockControllerContext(
this Controller controller, string path = null)
{
var mockHttpCtx = MockHttpHelper.MockHttpContext(path);
var requestCtx = new RequestContext(mockHttpCtx.Object, new RouteData());
var controllerCtx = new ControllerContext(requestCtx, controller);
controller.ControllerContext = controllerCtx;
return mockHttpCtx;
}
public static Mock<HttpContextBase> MockHttpContext(string path)
{
var mockHttpCtx = new Mock<HttpContextBase>();
var mockReq = new Mock<HttpRequestBase>();
mockReq.SetupGet(x => x.RequestType).Returns("GET");
mockReq.SetupGet(req => req.Form).Returns(new NameValueCollection());
mockReq.SetupGet(req => req.QueryString).Returns(new NameValueCollection());
mockHttpCtx.SetupGet(x => x.Request).Returns(mockReq.Object);
return mockHttpCtx;
}
}
Neither of these work, I get the exception below. Can anyone point me in the direction of a working example? I’ve seen quite a few questions on the net around the same topic, but given the date (posts from 2008-2010) and MVC version (i.e. 1 and 2) I feel like I’m missing something / or trying to mock more than I need to in MVC3.
System.NullReferenceException : Object reference not set to an instance of an object.
at System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ValueProviderFactoryCollection.<>c__DisplayClassc.<GetValueProvider>b__7(ValueProviderFactory factory)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList(IEnumerable`1 source)
at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.Controller.TryUpdateModel(TModel model)
Thanks
Yes, all you were really missing, as you've noted, was setting the Controller's ValueProvider. Even though you're using this controller with a Get action but no Post action, the Controller still gets its ValueProvider instantiated upon creation, so you need to do the same thing in your test scenario. Here's the base class that I use when testing my controllers. I use NBehave's NUnit wrapper for unit testing, so ignore the SpecBase reference if you wish
public abstract class MvcSpecBase<T> : SpecBase<T> where T : Controller
{
protected T Controller { get; set; }
protected string RelativePath = string.Empty;
protected string AbsolutePath = string.Empty;
protected void InitialiseController(T controller, NameValueCollection collection, params string[] routePaths)
{
Controller = controller;
var routes = new RouteCollection();
RouteConfig.RegisterRoutes(routes);
var httpContext = ContextHelper.FakeHttpContext(RelativePath, AbsolutePath, routePaths);
var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), Controller);
var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()), routes);
Controller.ControllerContext = context;
Controller.ValueProvider = new NameValueCollectionValueProvider(collection, CultureInfo.CurrentCulture);
Controller.Url = urlHelper;
}
}
Then, in your test, create your controller and then call this line:
InitialiseController(controller, new FormCollection());

asp.net active directory intranet

I have an intranet that gets the current logged in user through active directory. When a user is locked out they get a windows prompt to enter their username and password. Is there a way for me to catch this and redirect them to a page where they are asked to enter their credentials again or tell them that their account might be locked out and to contact the help desk?
On your application once you grab the user that is logged in do the IsAccountLocked method below
public bool IsAccountLocked(string sUserName)
{
UserPrincipal oUserPrincipal = GetUser(sUserName);
return oUserPrincipal.IsAccountLockedOut();
}
public UserPrincipal GetUser(string sUserName)
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = UserPrincipal.FindByIdentity(oPrincipalContext, sUserName);
return oUserPrincipal;
}
public PrincipalContext GetPrincipalContext()
{
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, sDomain, sDefaultOU, ContextOptions.SimpleBind, sServiceUser, sServicePassword);
return oPrincipalContext;
}
This is using System.DirectoryServices.AccountManagement for using only System.DirectoryServices you can do this
public bool IsAccountLocked(DirectoryEntry oDE)
{
return Convert.ToBoolean(oDE.InvokeGet("IsAccountLocked"));
}
public DirectoryEntry GetUser(string sUserName)
{
//Create an Instance of the DirectoryEntry
oDE = GetDirectoryObject();
//Create Instance fo the Direcory Searcher
oDS = new DirectorySearcher();
oDS.SearchRoot = oDE;
//Set the Search Filter
oDS.Filter = "(&(objectClass=user)(sAMAccountName=" + sUserName + "))";
oDS.SearchScope = SearchScope.Subtree;
oDS.PageSize = 10000;
//Find the First Instance
SearchResult oResults = oDS.FindOne();
//If found then Return Directory Object, otherwise return Null
if (oResults != null)
{
oDE = new DirectoryEntry(oResults.Path, sADUser, sADPassword, AuthenticationTypes.Secure);
return oDE;
}
else
{
return null;
}
}
private DirectoryEntry GetDirectoryObject()
{
oDE = new DirectoryEntry(sADPath, sADUser, sADPassword, AuthenticationTypes.Secure);
return oDE;
}
for a full implementation you can go to
http://anyrest.wordpress.com/2010/06/28/active-directory-c/
or
http://anyrest.wordpress.com/2010/02/01/active-directory-objects-and-c/

Resources