Je développe une application intranet ASP.NET MVC2 pour une petite entreprise. La petite entreprise a plusieurs types d'imprimantes et en fonction de ce qui est requis, une demande d'impression sera envoyée (du navigateur/utilisateur) au serveur et le serveur enverra le travail d'impression à la bonne imprimante en conséquence. S'il vous plaît noter que c'est un environnement complètement nouveau pour eux et j'ai le contrôle sur à peu près tout. Je vais plus que probablement utiliser un système d'exploitation très léger (peut-être Asus ExpressGate ou Chrome OS en fonction de la date de lancement?) Afin que les utilisateurs ne peuvent pas avoir d'imprimantes installées, mais le serveur aura tout configuré.Impression avec C#/ASP.NET MVC2
Voici ma question:
Y at-il un moyen simple d'imprimer à partir du côté serveur (sans dialogue bien sûr parce qu'il n'y aura plus personne en attente de cliquer dessus) une page en utilisant le lien html comme un paramètre et en gardant le format HTML bien sûr.
J'ai vu quelques possibilités de choses COM là-bas mais s'il y a des possibilités pour éviter cela en utilisant une classe .net j'apprécierais. J'utilise .net 4.0. Je prendrai cependant toutes les suggestions, même si elle est basée sur COM. S'il vous plaît noter que toute solution de contournement logique serait également pris en compte, un exemple rapide (pas encore étudié) serait de transférer ce fichier HTML dans un fichier doc et l'envoi de ce fichier à l'imprimante.
Code d'édition retiré pour cause d'inutilisation.
Edits2: suivant ce lien: Print html document from Windows Service in C# without print dialog
solution sainte graal de Vadim fonctionne. Cependant, il a des limitations comme l'utilisation de l'imprimante par défaut uniquement. Je suis en train de modifier l'imprimante par défaut avant que l'impression se produise, ce qui entraîne l'impression à la bonne imprimante. Je peux voir des problèmes d'adoption qui se passe ici, mais jusqu'à présent c'est le meilleur que je suis venu avec (la plupart de ce code est de Vadim et je lui donne tout le crédit pour cela):
/// <summary>Provides a scheduler that uses STA threads.</summary>
public sealed class StaTaskScheduler : TaskScheduler, IDisposable
{
/// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary>
private BlockingCollection<Task> _tasks;
/// <summary>The STA threads used by the scheduler.</summary>
private readonly List<Thread> _threads;
/// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary>
/// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
public StaTaskScheduler(int numberOfThreads)
{
// Validate arguments
if (numberOfThreads < 1) throw new ArgumentOutOfRangeException("concurrencyLevel");
// Initialize the tasks collection
_tasks = new BlockingCollection<Task>();
// Create the threads to be used by this scheduler
_threads = Enumerable.Range(0, numberOfThreads).Select(i =>
{
var thread = new Thread(() =>
{
// Continually get the next task and try to execute it.
// This will continue until the scheduler is disposed and no more tasks remain.
foreach (var t in _tasks.GetConsumingEnumerable())
{
TryExecuteTask(t);
}
});
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
return thread;
}).ToList();
// Start all of the threads
_threads.ForEach(t => t.Start());
}
/// <summary>Queues a Task to be executed by this scheduler.</summary>
/// <param name="task">The task to be executed.</param>
protected override void QueueTask(Task task)
{
// Push it into the blocking collection of tasks
_tasks.Add(task);
}
/// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary>
/// <returns>An enumerable of all tasks currently scheduled.</returns>
protected override IEnumerable<Task> GetScheduledTasks()
{
// Serialize the contents of the blocking collection of tasks for the debugger
return _tasks.ToArray();
}
/// <summary>Determines whether a Task may be inlined.</summary>
/// <param name="task">The task to be executed.</param>
/// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param>
/// <returns>true if the task was successfully inlined; otherwise, false.</returns>
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Try to inline if the current thread is STA
return
Thread.CurrentThread.GetApartmentState() == ApartmentState.STA &&
TryExecuteTask(task);
}
/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
public override int MaximumConcurrencyLevel
{
get { return _threads.Count; }
}
/// <summary>
/// Cleans up the scheduler by indicating that no more tasks will be queued.
/// This method blocks until all threads successfully shutdown.
/// </summary>
public void Dispose()
{
if (_tasks != null)
{
// Indicate that no new tasks will be coming in
_tasks.CompleteAdding();
// Wait for all threads to finish processing tasks
foreach (var thread in _threads) thread.Join();
// Cleanup
_tasks.Dispose();
_tasks = null;
}
}
}
public class PrinterHelper
{
readonly TaskScheduler _sta = new StaTaskScheduler(1);
public void PrintHtml(string htmlPath, string printerDevice)
{
if (!string.IsNullOrEmpty(printerDevice))
SetAsDefaultPrinter(printerDevice);
Task.Factory.StartNew(() => PrintOnStaThread(htmlPath), CancellationToken.None, TaskCreationOptions.None, _sta).Wait();
}
static void PrintOnStaThread(string htmlPath)
{
const short PRINT_WAITFORCOMPLETION = 2;
const int OLECMDID_PRINT = 6;
const int OLECMDEXECOPT_DONTPROMPTUSER = 2;
using(var browser = new WebBrowser())
{
browser.Navigate(htmlPath);
while(browser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
dynamic ie = browser.ActiveXInstance;
ie.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, PRINT_WAITFORCOMPLETION);
}
}
static void SetAsDefaultPrinter(string printerDevice)
{
foreach (var printer in PrinterSettings.InstalledPrinters)
{
//Verify that the printer exists here
}
var path = "win32_printer.DeviceId='" + printerDevice + "'";
using (var printer = new ManagementObject(path))
{
ManagementBaseObject outParams =
printer.InvokeMethod("SetDefaultPrinter",
null, null);
}
return;
}
}
Oui J'ai actuellement un assistant d'imprimante que j'ai trouvé ici dans stackoverflow que j'ai ajouté comme modification ci-dessus. Malheureusement, cela ne m'aide pas à imprimer un fichier rendu HTML jusqu'à présent. –
Je n'ai pas regardé mais est-il possible d'imprimer un flux? Si oui, vous pouvez potentiellement obtenir le code HTML créé, puis imprimer le flux de réponse qui comprend le code HTML ... juste une pensée folle :) – WestDiscGolf
En utilisant le code que je montre là-bas, cela fonctionne. Pour le besoin de ce projet cela fonctionne parce que c'est une petite entreprise. Je reconsidérerais probablement ceci était quelque chose qui allait être utilisé beaucoup plus en raison de la concurrence avec le changement de l'imprimante par défaut. Je déteste travailler avec des objets COM et celui-ci nécessite que IE soit installé sur le serveur, mais je dois faire ce que tu dois faire? Je suis toujours ouvert à d'autres suggestions plus évolutives! –