Я разрабатываю приложение ASP.NET MVC2 для интрасети для малого бизнеса. Малый бизнес имеет несколько типов принтеров, и в зависимости от того, что требуется, запрос на печать будет отправлен (от браузера/пользователя) на сервер, и сервер отправит задание на печать на правый принтер соответственно. Обратите внимание, что это совершенно новая среда для них, и я контролирую почти все. Я, скорее всего, буду использовать очень легкую ОС (возможно, Asus ExpressGate или Chrome OS в зависимости от даты запуска?), Поэтому пользователи не могут устанавливать какие-либо принтеры, но сервер будет иметь все настройки.Печать с использованием C#/ASP.NET MVC2
Вот мой вопрос:
Есть простой способ печати на стороне сервера (без диалога, конечно, потому что не будет никого ждать, чтобы нажимать на них) страницу, используя ссылку HTML, как параметр и сохранение формата HTML, конечно.
Я видел несколько возможностей COM-материалов там, но если есть возможности избежать этого, используя класс .net, я был бы признателен. Я использую .net 4.0. Однако я буду принимать любые предложения, даже если это COM.
Edit: Пожалуйста, обратите внимание, что любое решение, которое имеет смысл, также будет принято во внимание, быстро (пока не изучали) пример будет передать этот HTML в файл док и отправки этого файла на принтер.
Редактировать-Код снят из-за недостатков использования.
Edits2: После этой ссылке: Print html document from Windows Service in C# without print dialog
святой Грааль решение Вадима ДЕЛАЕТ работу. Тем не менее, он имеет ограничения, такие как использование только принтера по умолчанию. Я изменяю принтер по умолчанию перед началом печати, что приводит к тому, что печать переходит к правильному принтеру. Я могу видеть, что некоторые вопросы Совпадение здесь происходит, но до сих пор это лучшее, что я придумал (большая часть этого кода от Вадима, и я дал ему полный кредит для этого):
/// <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;
}
}
Да В настоящее время у меня есть помощник принтера, который я нашел здесь в stackoverflow, который я добавил как изменение выше. К сожалению, это не помогает мне печатать HTML-рендеринг файлов. –
Я не смотрел, но есть ли способ распечатать поток? Если это так, вы можете потенциально получить созданный html, а затем распечатать поток ответов, который включает html ... просто сумасшедшая мысль :) – WestDiscGolf
Используя код, который я показываю там, он работает. Для этого этот проект работает, потому что это небольшой бизнес. Я бы, вероятно, передумал, это было нечто, что будет использоваться намного больше из-за совпадения с изменением принтера по умолчанию. Мне не нравится работать с COM-объектами, и для этого требуется, чтобы IE был установлен на сервере, но должен делать то, что вам нужно делать? Я по-прежнему открыт для других более масштабируемых предложений! –