Reputation: 26907
ASP.NET Core hapily serves up files from the wwwroot
folder based on the mime type of the file. But how do I get it serve up a file with no extension?
As an example, Apple require that you have an endpoint in your app /apple-app-site-association
for some app-intergration. If you add a text file called apple-app-site-association into your wwwroot it won't work.
Some things I've tried:
1) Provide a mapping for when there's no extension:
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[""] = "text/plain";
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = provider
});
2) Adding an app rewrite:
var options = new RewriteOptions()
.AddRewrite("^apple-app-site-association","/apple-app-site-association.txt", false)
Neither work, the only thing that does work is a .AddRedirect
which I'd rather not use if possible.
Upvotes: 29
Views: 14461
Reputation: 8678
AspNetCore does not serve unknown file types for security reasons, but it should generally be safe to do for files in the .well-known
folder.
The problem is that Apple requires the correct MIME type for files without extensions, so we must explicitly configure those.
Solution
.well-known
folder.wwwroot/.well-known
folder.IContentTypeProvider
to map filenames to MIME type, such as apple-app-site-association
file name to application/json
MIME type.Startup.cs
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "wwwroot", ".well-known")),
RequestPath = "/.well-known",
ServeUnknownFileTypes = true,
ContentTypeProvider = new CustomWellKnownFileContentTypeProvider(),
});
CustomWellKnownFileContentTypeProvider.cs
/// <summary>
/// Custom file extension content type provider for serving certain extension-less files in .well-known folder.
/// <list type="bullet">
/// <item>apple-app-site-association - application/json - Apple Universal Link association</item>
/// </list>
/// </summary>
public class CustomWellKnownFileContentTypeProvider : IContentTypeProvider
{
private readonly FileExtensionContentTypeProvider _defaultProvider = new();
public bool TryGetContentType(string subpath, out string contentType)
{
// Custom handling of files without file extensions.
// Apple Universal Link association, requires the correct MIME type set.
if (subpath.EndsWith("apple-app-site-association", StringComparison.OrdinalIgnoreCase))
{
contentType = "application/json";
return true;
}
// Fallback to default provider, based on file extension.
if (_defaultProvider.TryGetContentType(subpath, out string? extContentType))
{
contentType = extContentType;
return true;
}
contentType = string.Empty;
return false;
}
}
Upvotes: 1
Reputation: 61
I think the easiest way is to add the apple-app-site-association file in a .well-known folder in the root folder of the application as described here: [https://developer.apple.com/documentation/safariservices/supporting_associated_domains] and then allow access to it from your code, like this (Startup.cs):
// to allow access to apple-app-site-association file
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, @".well-known")),
RequestPath = new PathString("/.well-known"),
DefaultContentType = "application/json",
ServeUnknownFileTypes = true,
});
Tested in AWS Serverless Application (.NET Core 3.1)
Upvotes: 6
Reputation: 41008
Rather than fighting with static files, I think you'd be better off just creating a controller for it:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using System.IO;
namespace MyApp.Controllers {
[Route("apple-app-site-association")]
public class AppleController : Controller {
private IHostingEnvironment _hostingEnvironment;
public AppleController(IHostingEnvironment environment) {
_hostingEnvironment = environment;
}
[HttpGet]
public async Task<IActionResult> Index() {
return Content(
await File.ReadAllTextAsync(Path.Combine(_hostingEnvironment.WebRootPath, "apple-app-site-association")),
"text/plain"
);
}
}
}
This assumes your apple-app-site-association
file is in your wwwroot folder.
Upvotes: 24
Reputation: 91
An easier option may be to put a file with a proper extension on the server, and then use URL rewrite as follows.
app.UseRewriter(new RewriteOptions()
.AddRewrite("(.*)/apple-app-site-association", "$1/apple-app-site-association.json", true));
Upvotes: 9
Reputation: 596
Adding an alternative solution. You have to set ServeUnknownFileTypes to true and after that set the default content type.
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "text/plain"
});
Upvotes: 40