System.Drawing in servizi Windows o ASP.NET

Secondo MSDN , non è particolarmente consigliabile utilizzare le classi all’interno dello spazio dei nomi System.Drawing in un servizio Windows o servizio ASP.NET. Ora sto sviluppando una libreria di classi che potrebbe aver bisogno di accedere a questo particolare spazio dei nomi (per misurare i caratteri) ma non può essere garantito che il processo host non sia un servizio.

Ora c’è un metodo meno ottimale a cui posso tornare se System.Drawing non è disponibile, ma se è ansible, preferisco usare le classi in System.Drawing. Quindi quello che mi piacerebbe fare è determinare a runtume se System.Drawing è sicuro o meno, e se lo è, usalo, altrimenti torna all’opzione suboptimale.

Il mio problema è: come posso rilevare se System.Drawing è sicuro da usare?

Penso che dovrei o

  • Rileva se il processo corrente è un servizio di Windows o un servizio ASP.NET
  • Rileva se GDI è disponibile
  • O forse c’è un modo per chiedere a System.Drawing.dll se è sicuro da usare

Sfortunatamente, non riesco a trovare un modo per attuare nessuno di questi approcci. Qualcuno ha qualche idea?

Per eliminare ogni confusione, System.Drawing funziona in ASP.NET e Servizi, non è supportato . Ci possono essere problemi con carico elevato (esaurimento delle risorse non gestite), perdite di memoria o risorse (implementate in modo errato o chiamate modelli di eliminazione) e / o windows di dialogo spuntate quando non c’è un desktop su cui mostrarle.

I test si prenderanno cura di quest’ultimo e il monitoraggio ti avviserà del primo. Ma, se / quando hai un problema, non aspettarti di essere in grado di chiamare PSS e chiedere una soluzione.

Quindi, quali sono le opzioni? Bene, se non hai bisogno di un percorso completamente supportato e non ti aspetti un carico estremo, molte persone hanno ignorato l’avvertenza MSDN e utilizzato System.Drawing con successo. Alcuni di loro sono stati morsi, ma ci sono molti più successi che storie di insuccessi.

Se vuoi qualcosa supportato, allora devi sapere se stai funzionando in modo interattivo o meno. Personalmente, probabilmente lascerei l’app di hosting per impostare un flag non interattivo da qualche parte. Dopotutto, l’app si trova nella posizione migliore per determinare se si trova in un ambiente ospitato e / o desidera rischiare problemi GDI +.

Ma, se vuoi rilevare automaticamente il tuo ambiente, suppongo ci siano risposte peggiori di quelle offerte qui da SO per un servizio. Per riassumere, puoi controllare EntryAssembly per vedere se eredita da ServiceBase o provare ad accedere a System.Console. Per ASP.NET, lungo le stesse linee, il rilevamento di HttpContext.Current dovrebbe essere sufficiente.

Penserei che ci sarebbe un modo gestito o p / invocare il modo di cercare un desktop (che è davvero il fattore determinante in tutto questo, penso) e / o qualcosa fuori dall’AppDomain che potrebbe indurti a entrare. Ma io Non sono sicuro di cosa sia, e MSDN è meno illuminante su di esso.

Modifica: Trolling MSDN, ho ricordato che in realtà è una Window Station (che ospita un desktop) che è il bit importante qui. Con queste informazioni, sono riuscito a trovare GetProcessWindowStation () che restituisce un handle alla stazione finestra corrente. Passando quell’handle a GetUserObjectInformation () otterrai una struttura USEROBJECTFLAGS con dovrebbe avere un dwFlags con WSF_VISIBLE se hai un desktop visibile.

In alternativa, EnumWindowsStations ti fornirà una lista di stazioni che potresti controllare – WinSta0 è quella intertriggers.

Ma, sì, continuo a pensare che avere l’app sia una proprietà o qualcosa sia la strada più facile …

Modifica di nuovo: 7 anni dopo, vengo a conoscenza di Environment.UserInteractive, dove MS esegue esattamente la danza GetProcessWindowStation che ho descritto sopra per te …. Consiglierei comunque di debind all’app di hosting (potrebbero volere il più veloce, ma leggermente più rischioso percorso System.Drawing), ma UserInteractive sembra avere un buon valore predefinito senza doverlo pinvoke tu stesso.

Anche se non è ufficialmente supportato, ho utilizzato le classi System.Drawing in modo estensivo su un server Web ad alto volume (sia per l’applicazione Web che per i servizi Web) per anni senza causare problemi di prestazioni o affidabilità.

Penso che l’unico modo per determinare se il codice è sicuro da usare è testare, monitorare e avvolgere qualsiasi object con risorse esterne usando le istruzioni {}.

Potresti usare TextRenderer invece. So che è strano usare qualcosa da System.Windows.Forms in ASP.NET, ma non sembra avere lo stesso avviso su non essere supportato in ASP.NET. Ho usato sia TextRenderer che Graphics.MeasureString per misurare le stringhe nelle applicazioni ASP.NET, quindi funzionano entrambe. Non avevo mai visto l’avviso che System.Drawing non fosse consigliabile in ASP.NET.

TextRenderer è molto più lento di Graphics.MeasureString, FWIW.

Potrebbe essere qualcosa a che fare con il sottosistema GDI che richiede un thread STA. Se questo è il caso, investigare specificando ASPCOMPAT = TRUE nella tua direttiva @PAGE per la pagina di aspx in questione. Questo eseguirà la pagina aspx in un thread STA, IIRC.

-Oisin

Potrebbe essere ansible copiare System.Drawing.dll nel contenitore dell’applicazione e quindi utilizzarlo in questo modo. Questo potrebbe garantire la sua disponibilità.

Basta fare clic con il tasto destro sul riferimento nella propria applicazione e modificare l’opzione Copia locale su vero .

Posso essere fraintendere la domanda però …