Domanda

Nei commenti di questa pagina:

http://msdn.microsoft .com / it-it / library / 12s31dhy% 28v = VS.90% 29.aspx

..it dice che TransmitFile () non può essere usato con condivisioni UNC. Per quanto ne so, questo è il caso; Ricevo questo errore nel registro eventi quando lo provo:

TransmitFile failed. File Name: \\myshare1\e$\file.zip, Impersonation Enabled: 0, Token Valid: 1, HRESULT: 0x8007052e

L'alternativa suggerita è quella di utilizzare WriteFile (), tuttavia, questo è problematico perché carica il file in memoria. Nella mia applicazione, i file sono & 200 MB, quindi questo non si ridimensionerà.

Esiste un metodo in ASP.NET per lo streaming di file agli utenti che è:

  • scalabile (non legge l'intero file nella RAM né occupa thread ASP.NET)
  • funziona con condivisioni UNC

Mappare un'unità di rete come directory virtuale non è un'opzione per noi. Vorrei evitare di copiare anche il file sul server Web locale.

Grazie

È stato utile?

Soluzione

Hai provato a configurare un vroot IIS usando il percorso UNC remoto come home directory? Se funziona, questa potrebbe essere la soluzione più semplice. Puoi comunque applicare barriere di autenticazione sui file (ad esempio tramite un HttpModule o forse anche tramite il modulo di autenticazione dei moduli out-of-box) ma puoi fare affidamento su IIS per lo streaming efficiente del contenuto una volta che i tuoi filtri di autenticazione danno il via libera.

Un avvertimento: l'ultima volta che ho configurato IIS in uno scenario UNC è stato molto tempo fa (1998 !!!) e ho riscontrato problemi intermittenti con i file bloccati sul computer remoto, rendendo l'aggiornamento dei file a volte problematico. Anche la gestione del ripristino dopo un riavvio del server UNC è stata interessante. Presumo che negli 11 anni da allora quei problemi siano stati risolti, ma non puoi mai esserne sicuro!

Un altro approccio potrebbe essere quello di installare un server Web sul computer UNC, quindi installare un server proxy inverso sul server Web, come il nuovo Modulo IIS7 Application Request Routing .

Se sei disposto a legare un thread del server, puoi utilizzare l'approccio consigliato in KB812406 che si occupa di problemi relativi al consumo di RAM, timeout, disconnessione del client, ecc. Assicurati di disattivare il buffering di risposta!

La soluzione ideale per il massimo controllo sarebbe un "streaming HttpHandler" dove, invece di dover inviare l'output tutto in una volta, è possibile restituire uno stream ad ASP.NET e lasciare che ASP.NET gestisca i dettagli relativi alla suddivisione dei risultati al client, alla gestione delle disconnessioni, ecc. un buon modo per farlo. : - (

Altri suggerimenti

Qualcosa che potresti provare è aprire il file di rete usando un FileStream , e usando un ciclo per leggere un pezzo del file, trasmettere il pezzo (usando Response.Write (Char [] , Int32, Int32) ), elimina il blocco e ripeti fino a quando il file non è stato letto completamente.

È possibile scrivere il file in una directory locale e fare in modo che un processo robocopy controlli la directory per eseguire la copia.

Dal momento che si desidera evitare di scrivere sul server locale, tuttavia, è possibile che si desideri investigare mettendo un server (HTTP o FTP, ad esempio) sul server di destinazione e scrivendo il file su quel servizio.

potresti creare un altro sito Web IIS che punta all'UNC, quindi reindirizzarli al file su quell'altro sito Web?

Response.Redirect (" http://files.somewhere.com/some/file .blah ");

In questo modo verrà eseguito in un processo di lavoro separato e non avrà alcun effetto sul tuo sito corrente e i file saranno serviti direttamente da IIS, il che è chiaramente il migliore.

L'errore reale che hai ricevuto è stato un errore di accesso alla condivisione file (il che non è molto sorprendente considerando che probabilmente anche IIS dell'utente sarà in esecuzione, così come stai tentando di accedere a una condivisione amministrativa). Hai provato a impostare una condivisione che non ha restrizioni di accesso solo per verificare se questo è il problema piuttosto che un limite specifico in TransmitFile.

Se risolto il problema, devi accedere a quella condivisione in un modo o nell'altro come l'utente corrente o impersonare un utente che dispone delle autorizzazioni.

Vale anche la pena sottolineare che dopo aver guardato in giro con il riflettore TransmitFile può potenzialmente finire per leggere il file in memoria comunque, e che WriteFile ha un'altra versione che accetta un valore booleano che decide se leggere il file in memoria o no (in effetti il ??WriteFile predefinito passa false per questo parametro). Potrebbe valerne la pena frugare nel codice.

Vorrei raccomandare il secondo approccio del sito e implementare un meccanismo di autenticazione basato su token. Codifica un cookie di autenticazione nell'URL passato al client tramite Redirect. Questo potrebbe essere un valore opaco condiviso dietro le quinte oppure potrebbe essere qualcosa di semplice come un hash di una password segreta e la data corrente, ad esempio.

Un progetto che ho usato ha usato l'hashing. Un server ha generato un hash di una password segreta condivisa e un numero di interno. Il secondo server (che si trovava su una rete diversa) ha preso la stessa password e estensione e li ha hash per confermare che all'utente è stato permesso di effettuare una chiamata da tale estensione al numero di telefono desiderato.

Il codice per TransmitFile è molto semplice, perché non modificarlo per fare ciò di cui hai bisogno?

public void TransmitFile(string filename, long offset, long length)
{
    if (filename == null)
    {
        throw new ArgumentNullException("filename");
    }
    if (offset < 0L)
    {
        throw new ArgumentException(SR.GetString("Invalid_range"), "offset");
    }
    if (length < -1L)
    {
        throw new ArgumentException(SR.GetString("Invalid_range"), "length");
    }
    filename = this.GetNormalizedFilename(filename);
    using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        long num = stream.Length;
        if (length == -1L)
        {
            length = num - offset;
        }
        if (num < offset)
        {
            throw new ArgumentException(SR.GetString("Invalid_range"), "offset");
        }
        if ((num - offset) < length)
        {
            throw new ArgumentException(SR.GetString("Invalid_range"), "length");
        }
        if (!this.UsingHttpWriter)
        {
            this.WriteStreamAsText(stream, offset, length);
            return;
        }
    }
    if (length > 0L)
    {
        bool supportsLongTransmitFile = (this._wr != null) && this._wr.SupportsLongTransmitFile;
        this._httpWriter.TransmitFile(filename, offset, length, this._context.IsClientImpersonationConfigured || HttpRuntime.IsOnUNCShareInternal, supportsLongTransmitFile);
    }
}



private void WriteStreamAsText(Stream f, long offset, long size)
{
    if (size < 0L)
    {
        size = f.Length - offset;
    }
    if (size > 0L)
    {
        if (offset > 0L)
        {
            f.Seek(offset, SeekOrigin.Begin);
        }
        byte[] buffer = new byte[(int) size];
        int count = f.Read(buffer, 0, (int) size);
        this._writer.Write(Encoding.Default.GetChars(buffer, 0, count));
    }
}


internal void TransmitFile(string filename, long offset, long size, bool isImpersonating, bool supportsLongTransmitFile)
{
    if (this._charBufferLength != this._charBufferFree)
    {
        this.FlushCharBuffer(true);
    }
    this._lastBuffer = null;
    this._buffers.Add(new HttpFileResponseElement(filename, offset, size, isImpersonating, supportsLongTransmitFile));
    if (!this._responseBufferingOn)
    {
        this._response.Flush();
    }
}

Grazie,

Phil.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top