Customizing web.config for ASP.NET 5 (vNext) deployments - asp.net-core

I'm using kpm pack to generate my deployment, which I deploy to Azure via ftp. I need to be able to serve static json files, so I need to add the following to my web.config:
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="text/html" />
</staticContent>
</system.webServer>
The problem is that kpm pack generates the web.config, so the only way to accomplish this is to add the config section to the web.config after it's been generated. Since I'm doing automated deployments via ci, this would require a bit of effort. Is there a better way to accomplish this?

You should add your configurations to the source of web.config, instead of the target.
If you don't have a web.config in root of the project being packed, please create one. Then add your static content configurations to [project_root]/web.config.
"kpm pack" will preserve all configurations in [project_root]/web.config, add some information needed by IIS, and then write it to wwwroot/web.config.
Important Update:
A change was introduced in "kpm pack": https://github.com/aspnet/KRuntime/pull/972
Please move your web.config from project root to the source of wwwroot.
The source of wwwroot folder can be specified with 'webroot' in project.json (https://github.com/aspnet/Home/wiki/Project.json-file#webroot).
You can also specify it with '--wwwroot' option of "kpm pack".

In ASP.NET Core you may be able to avoid web.config altogether by configuring the static file middleware options (StaticFileOptions) in code, providing a custom FileExtensionContentTypeProvider as its ContentTypeProvider:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddInstance<IContentTypeProvider>(
new FileExtensionConentTypeProvider(
new Dictionary<string, string>(
// Start with the base mappings
new FileExtensionContentTypeProvider().Mappings,
// Extend the base dictionary with your custom mappings
StringComparer.OrdinalIgnoreCase) {
{ ".json", "text/html" }
}
)
);
...
}
public void Configure(
IApplicationBuilder app,
IContentTypeProvider contentTypeProvider)
{
...
app.UseStaticFiles(new StaticFileOptions() {
ContentTypeProvider = contentTypeProvider
...
});
...
}

Related

Prevent Caching Views in ASP.NET Core in VS 19

I am new to ASP.NET core and I am trying to build a small web app but whenver I make a change to a view in debugging mode, I have to restart the application to see the new changes.
I tried few tricks but they did not work and even decorating a specific view with the filter
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
First, Install Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation NuGet package.
Second, Update the project's Startup.ConfigureServices method to include a call to AddRazorRuntimeCompilation.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages()
.AddRazorRuntimeCompilation();
// code omitted for brevity
}
Then you can update the page without restart the project.

How to serve static file from Asp .Net Core with period in directory name

I am currently trying to associate Apple Pay with a website. In order to verify the domain, Apple Pay requires that the website be able to serve a specific static file at https://websiteurl/.well-known/apple-developer-merchantid-domain-association.
I am currently unable to get my website to serve this static file. I am able to serve other static files, just not this specific one. I suppose the problem has something to do with the period in the directory name. I have tried to follow suggestions from this question but without success.
My wwwroot directory structure looks like this:
wwwroot
.well-known
apple-developer-merchantid-domain-association
web.config
App_Data
Content
css
js
app.js
lib
the contents of .well-known -> web.config is:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension="." mimeType="application/octet-stream" />
</staticContent>
</system.webServer>
</configuration>
I believe this is what what described in the accepted answer in this question.
However, when I attempt to access https://websiteurl/.well-known/apple-developer-merchantid-domain-association, I get an HTTP 404 error.
I verified that I can access static files successfully because https://websiteurl/js/app.js works successfully.
I also tried putting web.config directly under wwwroot
Not sure what I am doing wrong. Any suggestions?
Turns out the problem was not the period in the directory name, but rather the lack of extension on the file. The following code in Startup.cs solved the problem:
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/.well-known")),
RequestPath = "/.well-known",
ServeUnknownFileTypes = true,
DefaultContentType = "text/plain"
});
Try FileServer :
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
RequestPath = "/wwwroot",
EnableDirectoryBrowsing = true
});
}

appsettings.json file not in .net core console project

I understand that .net core has replaced the app.config file with appsetting.json. However this file seems to be added for ASP.net projects only. In fact it is not even available in the add items list.
I found this post that list packages needed to be added:
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Json
I added all these and it does give me the option of adding a json configuration file but still not the App Settings File which is only available under ASP.Net Core.
I am trying to understand why, doesn't a non web project need configuration and what is the recommended way to configure a .net core console application.
Thanks in advance.
Non-web project may or may not need configuration. But, as you noticed, Visual Studio doesn't scaffold console projects with appsettings.json. Obviously, you can add it to the project as json file. Once you have it, the challenge is to make use of it. I frequently use Configuration object and dependency injection in Entity Framework utilities.
For example,
public static class Program
{
private static IConfigurationRoot Configuration { get; set; }
public static void Main()
{
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
IServiceCollection services = new ServiceCollection();
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IMyService, MyService>();
IServiceProvider provider = services.BuildServiceProvider();
IMyService myService = provider.GetService<IMyService>();
myService.SomeMethod();
}
public class TemporaryDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
IConfigurationBuilder configBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
IConfigurationRoot configuration = configBuilder.Build();
DbContextOptionsBuilder<MyDbContext> builder = new DbContextOptionsBuilder<MyDbContext>();
builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
return new MyDbContext(builder.Options);
}
}
}
This allows me to both run migrations and console-based utilities against DbContext. You don't specify what kind of configuration you are going to need - so this is just one example. But hopefully, you can adjust it to your needs.

in asp.net 5 is it possible to store and read custom files in approot instead of wwwroot?

when you deploy an asp.net5/mvc6 app there is the wwwroot folder where web assets like css, js, images belong, and there is approot folder where packages and source code belong.
It seems that classes in the Microsoft.Framework.Configuration namespace for example must be able to read files from below approot since that is where config.json files would live.
What I want to know is, is it possible to store and read custom files of my own in approot? and if so how?
For example I'm not using Entity Framework so I need a place to put sql install and upgrade scripts and would prefer not to put them beneath wwwroot. I also have custom configuration files for things like navigation sitemap that I would rather not put below wwwroot if it is possible to put them elsewhere such as approot.
I know I can access files below wwwroot using IHostingEnvironment env.MapPath("~/somefileinwwwrootfoilder.json")
Is there a similar way to access files under approot?
The accepted answer is correct, but since a ASP.NET Core 1.0 release a few things have changed so I thought I'd write a new clear things up a bit.
What I did was create a folder in my project called AppData. You can call it anything you like.
Note: it's not in wwwroot because we want to keep this data private.
Next, you can use IHostingEnvironment to get access to the folder path. This interface can be injected as a dependency into some kind of helper service and what you end up with is something like this:
public class AppDataHelper
{
private readonly IHostingEnvironment _hostingEnvironment;
private const string _appDataFolder = "AppData";
public AppDataHelper(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
public async Task<string> ReadAllTextAsync(string relativePath)
{
var path = Path.Combine(_hostingEnvironment.ContentRootPath, _appDataFolder, relativePath);
using (var reader = File.OpenText(path))
{
return await reader.ReadToEndAsync();
}
}
}
Additionally, to get things to deploy correctly I had to add the AppData folder to the publishOptions include list in project.json.
As mentioned in the comments, to deploy AppData folder correctly in ASP.NET MVC Core 2 (using *.csproj file, instead of project.json), syntax is as follows:
<ItemGroup>
<None Include="AppData\*" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
Yes, it is possible. Just get the path to your app folder and the pass it to configuration or whoever else needs it:
public class Startup
{
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
var wwwrootRoot = env.WebRootPath;
var appRoot = appEnv.ApplicationBasePath;

web.config File Section Replacements

I have a web deployment project that does a web.config section replacement using an external file. (this is to change the connection strings section).
The web.config section replacement works fine when built manually, but when built as part of a TFS build the section is not replaced. I cannot find any errors or warnings in the build log.
What are the likely causes, or how can I 'debug' this?
Have you considered using Web.Config's ability to pull a section from a separate file? You refer to the external file like so (this is my code for loading a file that has my connection strings section):
<connectionStrings configSource="WebCS.config"/>
Then the connection string can be deployed as a separate file:
<connectionStrings>
<add name="ConnString" connectionString="Data Source=<server>;Initial Catalog=<DB>;User ID=<ID>;Password=<pwd>" providerName="System.Data.SqlClient"/>
</connectionStrings>
That way, you don't have to worry about changing the web.config file at all.
I am not sure this will help at all....but this is a way to add/update a connection string without having to replace the whole config section.
public static void SaveConfigVal(string connectionString, string connName)
{
System.Configuration.ExeConfigurationFileMap fileMap = new System.Configuration.ExeConfigurationFileMap();
fileMap.ExeConfigFilename = GetConfigFileName();
//System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
// Retrieve the section group
ConnectionStringSettings keyValue = config.ConnectionStrings.ConnectionStrings[connName];
// If the key already exists, just replace
if (keyValue != null)
{
keyValue.ConnectionString = connectionString;
}
else
{
// Add a new key if the setting doesn't exist
config.ConnectionStrings.ConnectionStrings.Add(new ConnectionStringSettings(connName, connectionString));
}
config.Save(ConfigurationSaveMode.Modified);// (ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("ConnectionStrings");
}
private static string GetConfigFileName()
{
//return config file name....
}
If you're using or can upgrade to Visual Studio 2010, you can utilize the new web.config transformations to alter the web.config based on selected configuration.
http://msdn.microsoft.com/en-us/library/dd465318.aspx