Cum de a suporta fișiere virtuale într-un site web C # MVC

voturi
21

Fac un catch-all site-ul în cazul în care utilizatorii pot încărca propriul lor cod HTML pe site-ul, atunci site-ul va afișa site-ul lor atunci când apelul lor subdomeniu specifice.

Codul HTML cu fișiere atașate obține este încărcat pe un subdirector în interiorul site-ului:

SITE #1
~/sites/test1/index.html
~/sites/test1/images/logo.png

SITE #2
~/sites/test2/index.html
~/sites/test2/images/logo.png

Deci, puteți apela aceste fișiere folosind următoarele adrese URL:

SITE #1
http://test1.mydomain.com/index.html
http://test1.mydomain.com/images/logo.png

SITE #2
http://test2.mydomain.com/index.html
http://test2.mydomain.com/images/logo.png

Deci, ce am făcut a fost să handler eroare în interiorul global.asax care detectează atunci când încercați să solicitați un fișier care nu există, prin urmare, să solicite site-ul:

protected void Application_Error()
{
    // Get the subdomain requested
    var subdomain = Request.Url.Authority.Split(new char[] { '.', ':' }).FirstOrDefault();

    // Get the directory info about the requested subdomain
    DirectoryInfo info = new DirectoryInfo(Server.MapPath(~/ + subdomain));

    // Check if subdomain is not empty and exists
    if (!string.IsNullOrEmpty(subdomain) && info.Exists)
    {
        // Get the requested filename
        var filename = Request.Url.PathAndQuery.Split(new char[] { '?' }).FirstOrDefault();

        // If the root is requested change to index.html
        if (filename == /) filename = /index.html;

        // Translate requested filename to server path
        var fullname = Server.MapPath(~/sites/ + subdomain + filename);

        // Respond the file
        ResponseFile(fullname);
    }
    else
    {
        // Subdomain not found so end the request
        Response.End();
    }
}

public void ResponseFile(string fullname)
{
    Response.Clear();

    System.IO.Stream oStream = null;

    try
    {
        // Open the file
        oStream =
            new System.IO.FileStream
                (path: fullname,
                mode: System.IO.FileMode.Open,
                share: System.IO.FileShare.Read,
                access: System.IO.FileAccess.Read);

        // **************************************************
        Response.Buffer = false;

        // Setting the ContentType
        Response.ContentType = MimeMapping.GetMimeMapping(fullname);

        // Get the length of the file 
        long lngFileLength = oStream.Length;

        // Notify user (client) the total file length
        Response.AddHeader(Content-Length, lngFileLength.ToString());
        // **************************************************

        // Total bytes that should be read
        long lngDataToRead = lngFileLength;

        // Read the bytes of file
        while (lngDataToRead > 0)
        {
            // The below code is just for testing! So we commented it!
            //System.Threading.Thread.Sleep(200);

            // Verify that the client is connected or not?
            if (Response.IsClientConnected)
            {
                // 8KB
                int intBufferSize = 8 * 1024;

                // Create buffer for reading [intBufferSize] bytes from file
                byte[] bytBuffers =
                    new System.Byte[intBufferSize];

                // Read the data and put it in the buffer.
                int intTheBytesThatReallyHasBeenReadFromTheStream =
                    oStream.Read(buffer: bytBuffers, offset: 0, count: intBufferSize);

                // Write the data from buffer to the current output stream.
                Response.OutputStream.Write
                    (buffer: bytBuffers, offset: 0,
                    count: intTheBytesThatReallyHasBeenReadFromTheStream);

                // Flush (Send) the data to output
                // (Don't buffer in server's RAM!)
                Response.Flush();

                lngDataToRead =
                    lngDataToRead - intTheBytesThatReallyHasBeenReadFromTheStream;
            }
            else
            {
                // Prevent infinite loop if user disconnected!
                lngDataToRead = -1;
            }
        }
    }
    catch { }
    finally
    {
        if (oStream != null)
        {
            //Close the file.
            oStream.Close();
            oStream.Dispose();
            oStream = null;
        }
        Response.Close();
        Response.End();
    }
}

Codul de mai sus funcționează pentru fișierul „/index.html“, dar aceasta nu funcționează pentru „/images/logo.png“, deoarece 404 nu se va declanșa handler Application_Error. După multe căutări și trăgând parul meu afară am aflat această „facilitate“ a pornit de la .net 4.0 și mai sus. Dar eu nu vreau să mă întorc, vreau să știu cum să rezolve în mod corespunzător acest lucru.

Întrebat 08/02/2018 la 19:48
de către utilizator
În alte limbi...                            


2 răspunsuri

voturi
3

În așteptare până la eroare aplicație este un pic mai târziu în conducta. O modalitate este de a crea un handler personalizat, și utilizând un traseu personalizat pentru a detecta fișiere virtuale aceste cereri handler. Acest lucru înseamnă că trebuie să generați link-uri către fișiere virtuale folosind un model previzibil, poate face o cale, cum ar fi / SpecialFiles /:

routes.Add(new Route("SpecialFiles/{*path}", new SomeFileHandler()));

Ai putea, de asemenea, harta asta aa acțiune controler, și lăsați acțiunea analiza adresa URL / șirul de interogare și returnează un răspuns fișier.

Fie abordare vă permite să specificați o rută cu diferiți parametri, cum ar fi un semn extrem de aleatoriu care este necesar pentru a accesa fișierul similar cu „fișierul partajat“ link-uri văzut în alte sisteme. Ai putea configura traseul pentru a se potrivi pe anumite extensii de fișiere. Opțiunile sunt destul de variate. La fel ca orice altă cale, puteți împinge diferite piese de calea în variabile, sau puteți accesa doar URL-ul direct de la solicitare după intrați în handler sau acțiune și analiza manual.

Publicat 08/02/2018 la 19:56
sursa de către utilizator

voturi
0

Datorită AaronLS, am început să caute cum să facă un handler personalizat, care ar prinde toate cererile. Păcat că nu a fost atât de ușor de găsit.

În primul rând, trebuie să informați IIS pe care doriți să se ocupe de toate fișierele prin actualizarea web.config:

<system.webServer>
    <httpErrors existingResponse="PassThrough" />
    <modules runAllManagedModulesForAllRequests="true">
        <remove name="FormsAuthentication"/>
    </modules>
</system.webServer>

(Nu - l cunosc httpErrors existingResponse = „passthrough“ într - adevăr este nevoie, ar fi fost o soluție anterioară am încercat)

Apoi am nevoie pentru a face propriul meu handler personalizat și setați-l în routeconfig:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // So my users can still login
        routes.MapRoute(
            name: "Account",
            url: "Account/{action}/{id}",
            defaults: new { controller = "Account", action = "Index", id = UrlParameter.Optional }
        );

        // For the upload controller to work
        routes.MapRoute(
            name: "Upload",
            url: "Upload/{action}/{id}",
            defaults: new { controller = "Upload", action = "Index", id = UrlParameter.Optional }
        );

        // And finally registrating my custom handler
        routes.Add(new Route("{*path}", new CustomRouteHandler()));

        // This was the original routeconfig
        //routes.MapRoute(
        //    name: "Default",
        //    url: "{controller}/{action}/{id}",
        //    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        //);
    }
}
public class CustomRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new CustomHttpHandler();
    }
}
public class CustomHttpHandler : IHttpHandler
{
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
    public void ProcessRequest(HttpContext context)
    {
        // Get the subdomain requested
        var subdomain = context.Request.Url.Authority.Split(new char[] { '.', ':' }).FirstOrDefault();

        // Get the directory info about the requested subdomain
        DirectoryInfo info = new DirectoryInfo(context.Server.MapPath("~/Websites/" + subdomain));

        // Check if subdomain is not empty and exists
        if (!string.IsNullOrEmpty(subdomain) && info.Exists)
        {
            // Get the requested filename
            var filename = context.Request.Url.PathAndQuery.Split(new char[] { '?' }).FirstOrDefault();

            // If the root is requested change to index.html
            if (filename == "/") filename = "/index.html";

            // Translate requested filename to server path
            var fullname = context.Server.MapPath("~/Websites/" + subdomain + filename);

            // Respond the file
            ResponseFile(context, fullname);
        }
        else
        {
            // Subdomain not found so end the request
            context.Response.End();
        }
    }
    public void ResponseFile(HttpContext context, string fullname)
    {
        // Clear the response buffer
        context.Response.Clear();

        System.IO.Stream oStream = null;

        try
        {
            // Open the file
            oStream =
                new System.IO.FileStream
                    (path: fullname,
                    mode: System.IO.FileMode.Open,
                    share: System.IO.FileShare.Read,
                    access: System.IO.FileAccess.Read);

            // **************************************************
            context.Response.Buffer = false;

            // Setting the ContentType
            context.Response.ContentType = MimeMapping.GetMimeMapping(fullname);

            // Get the length of the file 
            long lngFileLength = oStream.Length;

            // Notify user (client) the total file length
            context.Response.AddHeader("Content-Length", lngFileLength.ToString());
            // **************************************************

            // Total bytes that should be read
            long lngDataToRead = lngFileLength;

            // Read the bytes of file
            while (lngDataToRead > 0)
            {
                // Verify that the client is connected or not?
                if (context.Response.IsClientConnected)
                {
                    // 8KB
                    int intBufferSize = 8 * 1024;

                    // Create buffer for reading [intBufferSize] bytes from file
                    byte[] bytBuffers =
                        new System.Byte[intBufferSize];

                    // Read the data and put it in the buffer.
                    int intTheBytesThatReallyHasBeenReadFromTheStream =
                        oStream.Read(buffer: bytBuffers, offset: 0, count: intBufferSize);

                    // Write the data from buffer to the current output stream.
                    context.Response.OutputStream.Write
                        (buffer: bytBuffers, offset: 0,
                        count: intTheBytesThatReallyHasBeenReadFromTheStream);

                    // Flush (Send) the data to output
                    // (Don't buffer in server's RAM!)
                    context.Response.Flush();

                    lngDataToRead =
                        lngDataToRead - intTheBytesThatReallyHasBeenReadFromTheStream;
                }
                else
                {
                    // Prevent infinite loop if user disconnected!
                    lngDataToRead = -1;
                }
            }
        }
        catch (Exception e)
        {
        }
        finally
        {
            if (oStream != null)
            {
                //Close the file.
                oStream.Close();
                oStream.Dispose();
                oStream = null;
            }
            context.Response.Close();
            context.Response.End();
        }
    }
}
Publicat 27/03/2018 la 09:38
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more