14

New to ASP.NET MVC, I am creating a web application using the Visual Studio 2013 wizard. It creates several folders from where static files are served: Content, Scripts, etc.

Frameworks in other languages (e.g. TurboGears) have an explicit directory only for static content, removing the risk of serving the source code of a page instead of processing it which is a typical configuration mistake of PHP sites.

ASP.NET however is happy to deliver anything in the application's root directory, e.g. http://localhost:1740/Project_Readme.html as long as it has the right extension. Only the Views folder is protected with a Web.config.

How do I configure the application to use another directory than the project's root directory for static files. E.g. if the file favicon.ico is put into the subdirectory Content, it should be accessible as http://localhost:1740/favicon.ico, but nothing outside of the Content directory unless returned by a controller.

Nothing should ever be executed in this directory, that is, if *.cshtml files are put into this directory, the files' contents (the source code) should be delivered as text/plain.

Final application will run using mod_mono on Linux.

cassandrad
  • 3,412
  • 26
  • 50
Meinersbur
  • 7,881
  • 1
  • 27
  • 29
  • I guess this may help you: https://prerakkaushik.wordpress.com/2014/02/12/routing-request-for-static-files-with-or-without-extension-in-asp-net-mvc/ – Proggear May 24 '16 at 12:58
  • Unfortunately that solution only works when the request starts with Public, i need every thing except a single end point – ben or May 25 '16 at 10:57

2 Answers2

9

Update:

Ben,

The proposed solution works only with Owin. To get it working in an MVC application you have to use asp.net MVC 6 (part of asp.net core or asp.net 5) only. But, with Web API you can use the older versions too. To setup the application please use the following steps:

  1. Create an empty project using visual studio templates(don't select Web API or MVC)

  2. Add the following Nuget packages to the project:

    Microsoft.AspNet.WebApi

    Microsoft.AspNet.WebApi.Owin

    Microsoft.Owin.Host.SystemWeb

    Microsoft.Owin.StaticFiles

  3. Add a Startup.cs file and decorate the namespace with the following

[assembly: OwinStartup(typeof(Startup))]

  1. Add the following code to the Stratup.cs class

    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new {id = RouteParameter.Optional}
            );
        //Configure the file/ static file serving middleware
        var physicalFileSystem = new PhysicalFileSystem(@".\client");
        var fileServerOptions = new FileServerOptions
        {
            EnableDefaultFiles = true,
            RequestPath = PathString.Empty,
            FileSystem = physicalFileSystem
        };
    
        fileServerOptions.DefaultFilesOptions.DefaultFileNames = new[] {"index.html"};
        fileServerOptions.StaticFileOptions.ServeUnknownFileTypes = true;
        fileServerOptions.StaticFileOptions.FileSystem = physicalFileSystem;
        app.UseFileServer(fileServerOptions);
        app.UseWebApi(config);
    }
    
    1. This should do the magic. Now you can host the application in IIS. IIS will serve the static assets only from client folder. Add Server folder and add controllers.

The Microsoft.Owin.Host.SystemWeb is what facilitates the hosting of Owin application in IIS. The file serve options help IIS to serve static files only from client folder.

Please let me know if you have any questions.


Based on your question, the project structure that you want to achieve should be like the following.

Project Structure

Basically you will have two folders only, Client and Server. Static files are served from client folder only. Server folder is not accessible. If this is what you need then it can be achieved easily with Owin Self Host with Static File Serving middleware.

Self host works with out any dependency on IIS. But, if your planning to host this application on Linux, you could use Asp.NET CORE 1.0. Later if you decide to host the application on IIS inside windows that can be achieved easily by adding the Microsot.Owin.Host.SystemWeb nuget package.

There are great blog posts on this topic. This is the link for one of them. Here is the link for achieving the same in Asp.NET Core.

I hope this solves your issues and please let me know if you have any questions.

Thank you, Soma.

Soma Yarlagadda
  • 2,875
  • 3
  • 15
  • 37
  • You understood the question correctly but i didn't understand how to do it, I'm on windows. from your link i got var config = new HttpConfiguration(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); app.UseWebApi(config); app.UseFileServer(true); Where do i set the file path and the server path? How can i tell iis what to serve from where? Is it more efficent then just code? with the added Owin layer – ben or May 29 '16 at 06:52
  • Hi thank you for the bounty. If this solution answers your question, please mark my answer as accepted. Thank you. – Soma Yarlagadda May 31 '16 at 17:49
  • Thank you very much for your help, i didn't started that question so i can't accept the answer – ben or Jun 01 '16 at 08:11
  • Understood. Thank you for reply and please let me know if you have any questions. – Soma Yarlagadda Jun 01 '16 at 16:50
  • Works great! I also had to make a small change to web.config as described in this answer https://stackoverflow.com/a/36297940/5740181 – Daniel Elkington May 07 '19 at 00:02
3

The best solution I found is to ignore asp.net normal way and write a new way

        public override void Init()
        {
            BeginRequest -= OnBeginRequest;
            BeginRequest += OnBeginRequest;
        }


        protected void OnBeginRequest(object sender, EventArgs e)
        {
            if (Request.Url.AbsolutePath.StartsWith("/endPoint"))
            {
                Context.RemapHandler(endPoint);
            }
            else
            {
                Context.RemapHandler(staticHandler);
            }
        }

Let endPoint and staticHandler implement IHttpHandler it works but every static file moves through c# so there might be a solution with better performance

ben or
  • 653
  • 5
  • 17