I'm trying to initialize a database with sample data and I get an error:
Failed to set database initializer of type
'Blog.Models.DAL.BlogInitializer,Blog' for DbContext type
'Blog.Models.DAL.BlogContext, Blog' specified in the application
Inner exception is like that:
Can't find a file or an assembly 'Blog' or one of its dependencies.
Can't find the specified file.
I have Blog.Model and Blog.WebUI in separate projects in the same Blog solution.
I have edited Web.config (In Blog.WebUI) file like that:
<connectionStrings>
<add name="BlogContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=Blog;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<entityFramework>
<contexts>
<context type="Blog.Models.DAL.BlogContext, Blog">
<databaseInitializer type="Blog.Models.DAL.BlogInitializer, Blog" />
</context>
</contexts>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
In Server Explorer I see an accessible database created by it, but no tables inside.
BlogContext class:
namespace Blog.Models.DAL
{
public class BlogContext : DbContext
{
public BlogContext() : base("BlogContext")
{
}
public DbSet<Post> Posts { get; set; }
}
}
And initializer:
namespace Blog.Models.DAL
{
public class BlogInitializer : DropCreateDatabaseIfModelChanges<BlogContext>
{
protected override void Seed(BlogContext context)
{
var posts = new List<Post>
{
new Post { Title="sadasd", Content="asdsa", Date=DateTime.Parse("2016-11-13"), Language="pl" },
new Post { Title="sadasd", Content="asdsa", Date=DateTime.Parse("2016-11-13"), Language="pl" },
new Post { Title="sadasd", Content="asdsa", Date=DateTime.Parse("2016-11-13"), Language="pl" },
new Post { Title="sadasd", Content="asdsa", Date=DateTime.Parse("2016-11-13"), Language="pl" },
new Post { Title="sadasd", Content="asdsa", Date=DateTime.Parse("2016-11-13"), Language="pl" }
};
posts.ForEach(p => context.Posts.Add(p));
context.SaveChanges();
}
}
}
EF failed to instantiate the database initalizer for your DbContext instance named BlogContext.
In the configuration you have configured the correct value for type of your database initializer which is correct:
<contexts>
<context type="Blog.Models.DAL.BlogContext, Blog">
<databaseInitializer type="Blog.Models.DAL.BlogInitializer, Blog" />
</context>
</contexts>
The issue is that you're not using the correct assembly name Blog. You need to go to your project "Properties" via the context menu or Alt + F4 and copy the correct assembly name. Then put it like this:
<contexts>
<context type="Blog.Models.DAL.BlogContext, [The correct assemblby name]">
<databaseInitializer type="Blog.Models.DAL.BlogInitializer, [The correct assemblby name]" />
</context>
</contexts>
Related
My nlogconfig file is writing fine to a text file. It is also writing to a database when I include the connection string in appsettings.json. Now that we are ready to move to production, I am not going to be housing the connection string in appsettings.json.
However, the problem is that I do not know how to connect mynlogconfig file to a connection string that is located in Azure KeyVault.
How do I take this line of code in nlogconfig
connectionString="${configsetting:item=ConnectionStrings.DefaultConnection}"
and reference the connection string in Azure KeyVault?
My nlogconfig file:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
<add assembly="NLog.Appsettings.Standard"/>
</extensions>
<targets>
<!-- local file target -->
<target name="fileTarget"
xsi:type="File"
fileName="C:\Nlog\logs\meLog.txt"
layout="
-------------- ${level} (${longdate}) --------------${newline}
${newline}
Call Site: ${callsite}${newline}
Exception Type: ${exception:format=Type}${newline}
Exception Message: ${exception:format=Message}${newline}
Stack Trace: ${exception:format=StackTrace}${newline}
Additional Info: ${message}${newline}" />
<target xsi:type="Database"
name="dbTarget"
connectionString="${configsetting:item=ConnectionStrings.DefaultConnection}"
commandText="INSERT INTO Logs(CreatedOn,Message,Level,Exception,StackTrace,Logger,Url) VALUES (#datetime,#msg,#level,#exception,#trace,#logger,#url)">
<parameter name="#datetime" layout="${date}" />
<parameter name="#msg" layout="${message}" />
<parameter name="#level" layout="${level}" />
<parameter name="#exception" layout="${exception:format=#}" />
<parameter name="#trace" layout="${stacktrace}" />
<parameter name="#logger" layout="${logger}" />
<parameter name="#url" layout="${aspnet-request-url}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="dbTarget" />
<logger name="*" minlevel="Error" writeTo="fileTarget"/>
</rules>
</nlog>
My Program.cs file which is getting the database connection string from Azure KeyVault:
using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using WebApplication6.Models;
namespace WebApplication6
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
string MyClientID = "1MyClientID";
string MyTenantID = "1MyTenantID";
string MyClientSecretID = "1MyClientSecretID";
ClientSecretCredential credential =
new ClientSecretCredential(MyTenantID, MyClientID, MyClientSecretID);
var secretClient = new SecretClient(new Uri("https://somerandomurivault.vault.azure.net/"),
credential);
config.AddAzureKeyVault(secretClient, new KeyVaultSecretManager());
config.Build();
})
.ConfigureServices((hostContext, services)=>
{
var databaseConnectionString = hostContext.Configuration.GetValue<string>("databaseConnectionString");
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(databaseConnectionString);
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
I tried to set the connection string to a global variable, but I had no way of referencing this global variable in the nlogconfig file.
Is there an easy way to add a subdirectory in ASP.Net v4 Web API that would contain all of my client content? I have read a lot of articles today on virtual paths and routing, but nothing that quite describes this case.
For example, I want to store my images under wwwroot so when the the app receives this request:
http://myapp/img/logo.png
It fetches wwwroot\img\logo.png to handle the request. Obviously, I don't want to have to map out every file or folder individually.
There will be a Web API restful web service that will be handled by the regular routing functionality in WebApiConfig.cs.
(Note: I ask this because I plan to migrate our app to ASP.Net v5 when it is GA, and this would make moving the client-side code trivial)
You can use the Microsoft.Owin.FileSystem and Microsoft.Owin.StaticFiles NuGet Packages to achive what you want.
First add the two NuGet Packages.
Then add this Code to your Startup class:
public void Configuration(IAppBuilder app)
{
// here your other startup code like app.UseWebApi(config); etc.
ConfigureStaticFiles(app);
}
private void ConfigureStaticFiles(IAppBuilder app)
{
string root = AppDomain.CurrentDomain.BaseDirectory;
string wwwroot = Path.Combine(root, "wwwroot");
var fileServerOptions = new FileServerOptions()
{
EnableDefaultFiles = true,
EnableDirectoryBrowsing = false,
RequestPath = new PathString(string.Empty),
FileSystem = new PhysicalFileSystem(wwwroot)
};
fileServerOptions.StaticFileOptions.ServeUnknownFileTypes = true;
app.UseFileServer(fileServerOptions);
}
Also you have to make sure the handler is registered in your Web.config file. It should look like this:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
</handlers>
</system.webServer>
Then every file in your "wwwroot" Folder will be automatically accessible.
For example your wwwroot/img/logo.png file will be accessible via http://yourdomain.com/img/logo.png, just like you want it :)
If you generate the content of the wwwroot folder with npm/gulp/grunt in a build event, then maybe you also have to edit your csproj file and add this ItemGroup:
<ItemGroup>
<Content Include="wwwroot\**\*" />
</ItemGroup>
Add img folder to the root directory of your application. Also you have to to include images in the project or application
For handling file routing I would:
Create HttpHandler as workaround for Image handling/or some other static files.
Bundle config for configuring js and css file path.
Create HttpHandler for handling request to specific file extensions.
And modify the file real path using provided file relative path from the URL.
HttpHandler for .jpg files:
public class ServiceSettings
{
public static string RootStaticFolder = "\\wwwroot";
}
public class ImageHandler : IHttpHandler
{
public bool IsReusable { get { return false; } }
public void ProcessRequest(HttpContext context)
{
var fileSystemPath = context.Server.MapPath(Path.Combine("~") + ServiceSettings.RootStaticFolder);
var file = Path.Combine(Path.GetDirectoryName(context.Request.FilePath), Path.GetFileName(context.Request.FilePath));
var filePath = string.Concat(fileSystemPath, file);
if(!File.Exists(filePath))
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Status = "404 Not Found";
}
context.Response.WriteFile(filePath);
}
}
For making it work you must disable MVC routing for this king of files.
RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Disable routing for */*.jpg files
routes.IgnoreRoute("{*alljpg}", new { alljpg = #".*\.jpg(/.*)?" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Then you have to add registration for your HttpHandler to web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="false">
<remove name="FormsAuthentication" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="jpgs" verb="*" path="*.jpg" type="WebApplication1.ImageHandler" preCondition="managedHandler"/>
</handlers>
</system.webServer>
Also pay attention to runAllManagedModulesForAllRequests="false" setting in modules tag.
Bundle configuration for css/js files
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/wwwroot/Scripts/jquery-{version}.js"));
// Use the development version of Modernizr to develop with and learn from. Then, when you're
// ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/wwwroot/Scripts/modernizr-*"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/wwwroot/Scripts/bootstrap.js",
"~/wwwroot/Scripts/respond.js"));
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/wwwroot/Content/bootstrap.css",
"~/wwwroot/Content/site.css"));
}
With this approach it would be very easy during migration to asp.net 5.
You will only need to remove HttpHandler and bundle configurations.
I have an existing ASP.NET Membership database which I have to stick to. I'm developing a new MVC5 website in VS2013 (update 4) using a new MVC website project template. I have modified web.config to ensure the old Membership type of authentication is specified. I have also modified generated [HttpPost]Login action to ensure I login against my Membership database - it logs me in correctly and generates an authentication cookie as required.
However the website still redirects me to the Login page as I'm not authenticated. The Request.IsAuthenticated does show that I'm not authenticated. What am I missing? What are my options?
EDIT:
web.config changes (only changes):
<connectionStrings>
<add name="MyCS" connectionString="Data Source=sql1;Initial Catalog=MyDB;Persist Security Info=True;User ID=mysa;Password=mypw" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<authentication mode="Forms">
<forms timeout="20" name="seAdmin" loginUrl="~/Account/Login" />
</authentication>
<roleManager enabled="true" defaultProvider="CustomizedRoleProvider">
<providers>
<clear />
<add name="CustomizedRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="MyCS" applicationName="/seAdmin" />
</providers>
</roleManager>
<membership defaultProvider="CustomizedMembershipProvider">
<providers>
<clear />
<add name="CustomizedMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MyCS" applicationName="/seAdmin" />
</providers>
</membership>
<machineKey validationKey="63A7C07B191BA3EF02DD4866C420DCAB81C9FFCCC617DE40ED6E2B89A2FC2BA3FA32C39D183FE0708E9279C14E58318D0C5E171C0AF802F154430679D1778485" decryptionKey="F5B9049DECB8C9A23B1D131E63D2ED5C15FF0AEB3C3E96FC" validation="SHA1" />
</system.web>
Login action:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
if (Membership.ValidateUser(model.Email, model.Password))
{
FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1)
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
return View(model);
}
FilterConfig adds a global authorisation attribute
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AuthorizeAttribute() { Roles = "CWA" });
}
}
I have some theories as to why it doesn't work, firstly in web.config there is a <system.webServer> tag, there must be a line for removing FormsAuthentication, try commenting it out, or add one again, like so:
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
</modules>
secondly try User.Identity.IsAuthenticated to see it is false too, also are you have any role in your app?
Intranet application that needs to use Windows AD for authorization. Anyone will have access to the site, but only members of a specific AD group will have access to certain pages and API calls. The group name is in the web.config as it will vary by environment. I want to be able to use attributes on API controllers and methods:
[MyAdminAttribute]
public class MyController : ApiController
Here is my custom attribute:
public class MyAdminAttribute: AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var user = ((ApiController)actionContext.ControllerContext.Controller).User; // THIS USER IS ALWAYS NULL, WHY?
var adminGroup = WebConfigurationManager.AppSettings["MyAdminGroup"];
var isInAdminGroup = user.IsInRole(adminGroup);
var roles = ((ClaimsIdentity)user.Identity).Claims
.Where(c => c.Type == ClaimTypes.Role)
.Select(c => c.Value).ToList(); // Just checking here, 0 roles found.
return isInAdminGroup;
}
}
I also need to be able to check that the user is in the role within a Razor view:
#if (User.IsInRole(WebConfigurationManager.AppSettings["MyAdminGroup"])) {
Here are the relevent web.config settings:
<authentication mode="Windows"/>
<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
<providers>
<clear />
<add
name="AspNetWindowsTokenRoleProvider"
type="System.Web.Security.WindowsTokenRoleProvider"
applicationName="/" />
</providers>
</roleManager>
However, the User is always null and User.IsInRole() is always false. Why would this be occuring?
I am trying to implement Asp.net Forms Authentication in my site. Usually, you provide the name of your DB connection string in your web.config. However, as our database setup is a little more complicated, I was looking for a way to manually provide the MembershipProvider the connection string in code.
Thanks!
You don't have to use a connectionStringName for SqlMembershipProvider, instead you can supply the connection string directly. I.e. instead of:
<membership defaultProvider="SqlProvider" ...>
<providers>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider"
connectionStringName="MyConnectionStringName"
.../>
</providers>
</membership>
You can specify the connection string directly as:
<membership defaultProvider="SqlProvider" ...>
<providers>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider"
connectionString="data source=... "
.../>
</providers>
</membership>
Therefore you could also derive a custom provider from SqlMembershipProvider, and build the connection string dynamically as follows:
public class MySqlMembershipProvider : SqlMembershipProvider
{
public override void Initialize(string name, NameValueCollection config)
{
config["connectionString"] = BuildMyCustomConnectionString();
base.Initialize(name, config);
}
}
I came across this needing to do the same thing, set the connection string via code and not in the web.config, although I needed to change more than the name, I needed the actual value to be dynamically generated. If you want to change the actual connection string to be generated from code you can do the following:
web.config
...
<connectionStrings>
<add name="ConnectionPlaceHolder" connectionString="This is a place holder"/>
</connectionStrings>
...
<roleManager defaultProvider="SqlRoleProvider" enabled="true">
<providers>
<clear/>
<add name="SqlRoleProvider" type="MyClassLibraries.Web.Security.MyCustomSqlRoleProvider" connectionStringName="ConnectionPlaceHolder" applicationName="MyApplicationName"/>
</providers>
</roleManager>
Provider Class
public class MySqlRoleProvider : SqlRoleProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
try
{
config["connectionStringName"] = "ConnectionPlaceHolder";
base.Initialize(name, config);
FieldInfo connectionStringField = GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
connectionStringField.SetValue(this, ApplicationConfiguration.RetrieveApplicationConfigurationValue(myConnectionString));
}
catch (Exception ex)
{
CurrentOperation.RaiseException(ex);
throw ex;
}
}
private string myConnectionString()
{
return "Server=MyServer;database=MyDB;uid=aspnetDBUser;pwd=myPassword"
}
}
When you call base.Initialize() the .NET class requires there be a name specified in the web.config which is why you have to put something, so I just used a placeholder since I knew I would be overriding it in the code.
Our team did this because we needed to dynamically build connection strings based on different environments and didn't want to have to worry about having multiple web.configs floating around.