PrintService.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. // Copyright (c) 2012-2020 fo-dicom contributors.
  2. // Licensed under the Microsoft Public License (MS-PL).
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using Dicom.Network;
  9. namespace Dicom.Printing
  10. {
  11. public class PrintService : DicomService, IDicomServiceProvider, IDicomNServiceProvider, IDicomCEchoProvider
  12. {
  13. #region Properties and Attributes
  14. private static readonly DicomTransferSyntax[] AcceptedTransferSyntaxes = new DicomTransferSyntax[]
  15. {
  16. DicomTransferSyntax.ExplicitVRLittleEndian,
  17. DicomTransferSyntax.ExplicitVRBigEndian,
  18. DicomTransferSyntax.ImplicitVRLittleEndian
  19. };
  20. private static IDicomServer _server;
  21. public static Printer Printer { get; private set; }
  22. public string CallingAE { get; protected set; }
  23. public string CalledAE { get; protected set; }
  24. public System.Net.IPAddress RemoteIP { get; private set; }
  25. private FilmSession _filmSession;
  26. private readonly Dictionary<string, PrintJob> _printJobList = new Dictionary<string, PrintJob>();
  27. private bool _sendEventReports = false;
  28. private readonly object _synchRoot = new object();
  29. #endregion
  30. #region Constructors and Initialization
  31. public PrintService(INetworkStream stream, Encoding fallbackEncoding, Log.Logger log)
  32. : base(stream, fallbackEncoding, log)
  33. {
  34. var pi = stream.GetType()
  35. .GetProperty(
  36. "Socket",
  37. System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
  38. if (pi != null)
  39. {
  40. var endPoint =
  41. ((System.Net.Sockets.Socket)pi.GetValue(stream, null)).RemoteEndPoint as System.Net.IPEndPoint;
  42. RemoteIP = endPoint.Address;
  43. }
  44. else
  45. {
  46. RemoteIP = new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 });
  47. }
  48. }
  49. public static void Start(int port, string aet)
  50. {
  51. Printer = new Printer(aet);
  52. _server = DicomServer.Create<PrintService>(port);
  53. }
  54. public static void Stop()
  55. {
  56. _server.Dispose();
  57. }
  58. #endregion
  59. #region IDicomServiceProvider Members
  60. public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
  61. {
  62. Logger.Info("Received association request from AE: {0} with IP: {1} ", association.CallingAE, RemoteIP);
  63. if (Printer.PrinterAet != association.CalledAE)
  64. {
  65. Logger.Error(
  66. "Association with {0} rejected since requested printer {1} not found",
  67. association.CallingAE,
  68. association.CalledAE);
  69. return SendAssociationRejectAsync(
  70. DicomRejectResult.Permanent,
  71. DicomRejectSource.ServiceUser,
  72. DicomRejectReason.CalledAENotRecognized);
  73. }
  74. CallingAE = association.CallingAE;
  75. CalledAE = Printer.PrinterAet;
  76. foreach (var pc in association.PresentationContexts)
  77. {
  78. if (pc.AbstractSyntax == DicomUID.Verification
  79. || pc.AbstractSyntax == DicomUID.BasicGrayscalePrintManagementMetaSOPClass
  80. || pc.AbstractSyntax == DicomUID.BasicColorPrintManagementMetaSOPClass
  81. || pc.AbstractSyntax == DicomUID.PrinterSOPClass
  82. || pc.AbstractSyntax == DicomUID.BasicFilmSessionSOPClass
  83. || pc.AbstractSyntax == DicomUID.BasicFilmBoxSOPClass
  84. || pc.AbstractSyntax == DicomUID.BasicGrayscaleImageBoxSOPClass
  85. || pc.AbstractSyntax == DicomUID.BasicColorImageBoxSOPClass)
  86. {
  87. pc.AcceptTransferSyntaxes(AcceptedTransferSyntaxes);
  88. }
  89. else if (pc.AbstractSyntax == DicomUID.PrintJobSOPClass)
  90. {
  91. pc.AcceptTransferSyntaxes(AcceptedTransferSyntaxes);
  92. _sendEventReports = true;
  93. }
  94. else
  95. {
  96. Logger.Warn(
  97. "Requested abstract syntax {abstractSyntax} from {callingAE} not supported",
  98. pc.AbstractSyntax,
  99. association.CallingAE);
  100. pc.SetResult(DicomPresentationContextResult.RejectAbstractSyntaxNotSupported);
  101. }
  102. }
  103. Logger.Info("Accepted association request from {callingAE}", association.CallingAE);
  104. return SendAssociationAcceptAsync(association);
  105. }
  106. public Task OnReceiveAssociationReleaseRequestAsync()
  107. {
  108. Clean();
  109. return SendAssociationReleaseResponseAsync();
  110. }
  111. public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
  112. {
  113. //stop printing operation
  114. //log the abort reason
  115. Logger.Error("Received abort from {0}, reason is {1}", source, reason);
  116. }
  117. public void OnConnectionClosed(Exception exception)
  118. {
  119. Clean();
  120. }
  121. #endregion
  122. #region IDicomCEchoProvider Members
  123. public DicomCEchoResponse OnCEchoRequest(DicomCEchoRequest request)
  124. {
  125. Logger.Info("Received verification request from AE {0} with IP: {1}", CallingAE, RemoteIP);
  126. return new DicomCEchoResponse(request, DicomStatus.Success);
  127. }
  128. #endregion
  129. #region N-CREATE requests handlers
  130. public DicomNCreateResponse OnNCreateRequest(DicomNCreateRequest request)
  131. {
  132. lock (_synchRoot)
  133. {
  134. if (request.SOPClassUID == DicomUID.BasicFilmSessionSOPClass)
  135. {
  136. return CreateFilmSession(request);
  137. }
  138. else if (request.SOPClassUID == DicomUID.BasicFilmBoxSOPClass)
  139. {
  140. return CreateFilmBox(request);
  141. }
  142. else
  143. {
  144. return new DicomNCreateResponse(request, DicomStatus.SOPClassNotSupported);
  145. }
  146. }
  147. }
  148. private DicomNCreateResponse CreateFilmSession(DicomNCreateRequest request)
  149. {
  150. if (_filmSession != null)
  151. {
  152. Logger.Error("Attemted to create new basic film session on association with {0}", CallingAE);
  153. SendAbortAsync(DicomAbortSource.ServiceProvider, DicomAbortReason.NotSpecified).Wait();
  154. return new DicomNCreateResponse(request, DicomStatus.NoSuchObjectInstance);
  155. }
  156. var pc = request.PresentationContext;
  157. bool isColor = pc != null && pc.AbstractSyntax == DicomUID.BasicColorPrintManagementMetaSOPClass;
  158. _filmSession = new FilmSession(request.SOPClassUID, request.SOPInstanceUID, request.Dataset, isColor);
  159. Logger.Info("Create new film session {0}", _filmSession.SOPInstanceUID.UID);
  160. if (request.SOPInstanceUID == null || request.SOPInstanceUID.UID == string.Empty)
  161. {
  162. request.Command.AddOrUpdate(DicomTag.AffectedSOPInstanceUID, _filmSession.SOPInstanceUID);
  163. }
  164. var response = new DicomNCreateResponse(request, DicomStatus.Success);
  165. return response;
  166. }
  167. private DicomNCreateResponse CreateFilmBox(DicomNCreateRequest request)
  168. {
  169. if (_filmSession == null)
  170. {
  171. Logger.Error("A basic film session does not exist for this association {0}", CallingAE);
  172. SendAbortAsync(DicomAbortSource.ServiceProvider, DicomAbortReason.NotSpecified).Wait();
  173. return new DicomNCreateResponse(request, DicomStatus.NoSuchObjectInstance);
  174. }
  175. var filmBox = _filmSession.CreateFilmBox(request.SOPInstanceUID, request.Dataset);
  176. if (!filmBox.Initialize())
  177. {
  178. Logger.Error("Failed to initialize requested film box {0}", filmBox.SOPInstanceUID.UID);
  179. SendAbortAsync(DicomAbortSource.ServiceProvider, DicomAbortReason.NotSpecified).Wait();
  180. return new DicomNCreateResponse(request, DicomStatus.ProcessingFailure);
  181. }
  182. Logger.Info("Created new film box {0}", filmBox.SOPInstanceUID.UID);
  183. if (request.SOPInstanceUID == null || request.SOPInstanceUID.UID == string.Empty)
  184. {
  185. request.Command.AddOrUpdate(DicomTag.AffectedSOPInstanceUID, filmBox.SOPInstanceUID.UID);
  186. }
  187. return new DicomNCreateResponse(request, DicomStatus.Success)
  188. {
  189. Dataset = filmBox
  190. };
  191. }
  192. #endregion
  193. #region N-DELETE request handler
  194. public DicomNDeleteResponse OnNDeleteRequest(DicomNDeleteRequest request)
  195. {
  196. lock (_synchRoot)
  197. {
  198. if (request.SOPClassUID == DicomUID.BasicFilmSessionSOPClass)
  199. {
  200. return DeleteFilmSession(request);
  201. }
  202. else if (request.SOPClassUID == DicomUID.BasicFilmBoxSOPClass)
  203. {
  204. return DeleteFilmBox(request);
  205. }
  206. else
  207. {
  208. return new DicomNDeleteResponse(request, DicomStatus.NoSuchSOPClass);
  209. }
  210. }
  211. }
  212. private DicomNDeleteResponse DeleteFilmBox(DicomNDeleteRequest request)
  213. {
  214. if (_filmSession == null)
  215. {
  216. Logger.Error("Can't delete a basic film session doesnot exist for this association {0}", CallingAE);
  217. return new DicomNDeleteResponse(request, DicomStatus.NoSuchObjectInstance);
  218. }
  219. DicomStatus status =
  220. _filmSession.DeleteFilmBox(request.SOPInstanceUID)
  221. ? DicomStatus.Success
  222. : DicomStatus.NoSuchObjectInstance;
  223. var response = new DicomNDeleteResponse(request, status);
  224. return response;
  225. }
  226. private DicomNDeleteResponse DeleteFilmSession(DicomNDeleteRequest request)
  227. {
  228. if (_filmSession == null)
  229. {
  230. Logger.Error("Can't delete a basic film session doesnot exist for this association {0}", CallingAE);
  231. return new DicomNDeleteResponse(request, DicomStatus.NoSuchObjectInstance);
  232. }
  233. if (!request.SOPInstanceUID.Equals(_filmSession.SOPInstanceUID))
  234. {
  235. Logger.Error(
  236. "Can't delete a basic film session with instace UID {0} doesnot exist for this association {1}",
  237. request.SOPInstanceUID.UID,
  238. CallingAE);
  239. return new DicomNDeleteResponse(request, DicomStatus.NoSuchObjectInstance);
  240. }
  241. _filmSession = null;
  242. return new DicomNDeleteResponse(request, DicomStatus.Success);
  243. }
  244. #endregion
  245. #region N-SET request handler
  246. public DicomNSetResponse OnNSetRequest(DicomNSetRequest request)
  247. {
  248. lock (_synchRoot)
  249. {
  250. if (request.SOPClassUID == DicomUID.BasicFilmSessionSOPClass)
  251. {
  252. return SetFilmSession(request);
  253. }
  254. else if (request.SOPClassUID == DicomUID.BasicFilmBoxSOPClass)
  255. {
  256. return SetFilmBox(request);
  257. }
  258. else if (request.SOPClassUID == DicomUID.BasicColorImageBoxSOPClass
  259. || request.SOPClassUID == DicomUID.BasicGrayscaleImageBoxSOPClass)
  260. {
  261. return SetImageBox(request);
  262. }
  263. else
  264. {
  265. return new DicomNSetResponse(request, DicomStatus.SOPClassNotSupported);
  266. }
  267. }
  268. }
  269. private DicomNSetResponse SetImageBox(DicomNSetRequest request)
  270. {
  271. if (_filmSession == null)
  272. {
  273. Logger.Error("A basic film session does not exist for this association {0}", CallingAE);
  274. return new DicomNSetResponse(request, DicomStatus.NoSuchObjectInstance);
  275. }
  276. Logger.Info("Set image box {0}", request.SOPInstanceUID.UID);
  277. var imageBox = _filmSession.FindImageBox(request.SOPInstanceUID);
  278. if (imageBox == null)
  279. {
  280. Logger.Error(
  281. "Received N-SET request for invalid image box instance {0} for this association {1}",
  282. request.SOPInstanceUID.UID,
  283. CallingAE);
  284. return new DicomNSetResponse(request, DicomStatus.NoSuchObjectInstance);
  285. }
  286. request.Dataset.CopyTo(imageBox);
  287. return new DicomNSetResponse(request, DicomStatus.Success);
  288. }
  289. private DicomNSetResponse SetFilmBox(DicomNSetRequest request)
  290. {
  291. if (_filmSession == null)
  292. {
  293. Logger.Error("A basic film session does not exist for this association {0}", CallingAE);
  294. return new DicomNSetResponse(request, DicomStatus.NoSuchObjectInstance);
  295. }
  296. Logger.Info("Set film box {0}", request.SOPInstanceUID.UID);
  297. var filmBox = _filmSession.FindFilmBox(request.SOPInstanceUID);
  298. if (filmBox == null)
  299. {
  300. Logger.Error(
  301. "Received N-SET request for invalid film box {0} from {1}",
  302. request.SOPInstanceUID.UID,
  303. CallingAE);
  304. return new DicomNSetResponse(request, DicomStatus.NoSuchObjectInstance);
  305. }
  306. request.Dataset.CopyTo(filmBox);
  307. filmBox.Initialize();
  308. var response = new DicomNSetResponse(request, DicomStatus.Success);
  309. response.Command.AddOrUpdate(DicomTag.AffectedSOPInstanceUID, filmBox.SOPInstanceUID);
  310. response.Dataset = filmBox;
  311. return response;
  312. }
  313. private DicomNSetResponse SetFilmSession(DicomNSetRequest request)
  314. {
  315. if (_filmSession == null || _filmSession.SOPInstanceUID.UID != request.SOPInstanceUID.UID)
  316. {
  317. Logger.Error("A basic film session does not exist for this association {0}", CallingAE);
  318. return new DicomNSetResponse(request, DicomStatus.NoSuchObjectInstance);
  319. }
  320. Logger.Info("Set film session {0}", request.SOPInstanceUID.UID);
  321. request.Dataset.CopyTo(_filmSession);
  322. return new DicomNSetResponse(request, DicomStatus.Success);
  323. }
  324. #endregion
  325. #region N-GET request handler
  326. public DicomNGetResponse OnNGetRequest(DicomNGetRequest request)
  327. {
  328. lock (_synchRoot)
  329. {
  330. Logger.Info(request.ToString(true));
  331. if (request.SOPClassUID == DicomUID.PrinterSOPClass
  332. && request.SOPInstanceUID == DicomUID.PrinterSOPInstance)
  333. {
  334. return GetPrinter(request);
  335. }
  336. else if (request.SOPClassUID == DicomUID.PrintJobSOPClass)
  337. {
  338. return GetPrintJob(request);
  339. }
  340. else if (request.SOPClassUID == DicomUID.PrinterConfigurationRetrievalSOPClass
  341. && request.SOPInstanceUID == DicomUID.PrinterConfigurationRetrievalSOPInstance)
  342. {
  343. return GetPrinterConfiguration(request);
  344. }
  345. else
  346. {
  347. return new DicomNGetResponse(request, DicomStatus.NoSuchSOPClass);
  348. }
  349. }
  350. }
  351. private DicomNGetResponse GetPrinter(DicomNGetRequest request)
  352. {
  353. var ds = new DicomDataset();
  354. var sb = new StringBuilder();
  355. if (request.Attributes != null && request.Attributes.Length > 0)
  356. {
  357. foreach (var item in request.Attributes)
  358. {
  359. sb.AppendFormat("GetPrinter attribute {0} requested", item);
  360. sb.AppendLine();
  361. var value = Printer.GetSingleValueOrDefault(item, "");
  362. ds.Add(item, value);
  363. }
  364. Logger.Info(sb.ToString());
  365. }
  366. if (!ds.Any())
  367. {
  368. ds.Add(DicomTag.PrinterStatus, Printer.PrinterStatus);
  369. ds.Add(DicomTag.PrinterStatusInfo, "");
  370. ds.Add(DicomTag.PrinterName, Printer.PrinterName);
  371. ds.Add(DicomTag.Manufacturer, Printer.Manufacturer);
  372. ds.Add(DicomTag.DateOfLastCalibration, Printer.DateTimeOfLastCalibration.Date);
  373. ds.Add(DicomTag.TimeOfLastCalibration, Printer.DateTimeOfLastCalibration);
  374. ds.Add(DicomTag.ManufacturerModelName, Printer.ManufacturerModelName);
  375. ds.Add(DicomTag.DeviceSerialNumber, Printer.DeviceSerialNumber);
  376. ds.Add(DicomTag.SoftwareVersions, Printer.SoftwareVersions);
  377. }
  378. var response = new DicomNGetResponse(request, DicomStatus.Success)
  379. {
  380. Dataset = ds
  381. };
  382. Logger.Info(response.ToString(true));
  383. return response;
  384. }
  385. private DicomNGetResponse GetPrinterConfiguration(DicomNGetRequest request)
  386. {
  387. var dataset = new DicomDataset();
  388. var config = new DicomDataset();
  389. var sequence = new DicomSequence(DicomTag.PrinterConfigurationSequence, config);
  390. dataset.Add(sequence);
  391. var response = new DicomNGetResponse(request, DicomStatus.Success);
  392. response.Command.AddOrUpdate(DicomTag.AffectedSOPInstanceUID, request.SOPInstanceUID);
  393. response.Dataset = dataset;
  394. return response;
  395. }
  396. private DicomNGetResponse GetPrintJob(DicomNGetRequest request)
  397. {
  398. if (_printJobList.ContainsKey(request.SOPInstanceUID.UID))
  399. {
  400. var printJob = _printJobList[request.SOPInstanceUID.UID];
  401. var sb = new StringBuilder();
  402. var dataset = new DicomDataset();
  403. if (request.Attributes != null && request.Attributes.Length > 0)
  404. {
  405. foreach (var item in request.Attributes)
  406. {
  407. sb.AppendFormat("GetPrintJob attribute {0} requested", item);
  408. sb.AppendLine();
  409. var value = printJob.GetSingleValueOrDefault(item, "");
  410. dataset.Add(item, value);
  411. }
  412. Logger.Info(sb.ToString());
  413. }
  414. var response = new DicomNGetResponse(request, DicomStatus.Success)
  415. {
  416. Dataset = dataset
  417. };
  418. return response;
  419. }
  420. else
  421. {
  422. var response = new DicomNGetResponse(request, DicomStatus.NoSuchObjectInstance);
  423. return response;
  424. }
  425. }
  426. #endregion
  427. #region N-ACTION request handler
  428. public DicomNActionResponse OnNActionRequest(DicomNActionRequest request)
  429. {
  430. if (_filmSession == null)
  431. {
  432. Logger.Error("A basic film session does not exist for this association {0}", CallingAE);
  433. return new DicomNActionResponse(request, DicomStatus.InvalidObjectInstance);
  434. }
  435. lock (_synchRoot)
  436. {
  437. try
  438. {
  439. var filmBoxList = new List<FilmBox>();
  440. if (request.SOPClassUID == DicomUID.BasicFilmSessionSOPClass && request.ActionTypeID == 0x0001)
  441. {
  442. Logger.Info("Creating new print job for film session {0}", _filmSession.SOPInstanceUID.UID);
  443. filmBoxList.AddRange(_filmSession.BasicFilmBoxes);
  444. }
  445. else if (request.SOPClassUID == DicomUID.BasicFilmBoxSOPClass && request.ActionTypeID == 0x0001)
  446. {
  447. Logger.Info("Creating new print job for film box {0}", request.SOPInstanceUID.UID);
  448. var filmBox = _filmSession.FindFilmBox(request.SOPInstanceUID);
  449. if (filmBox != null)
  450. {
  451. filmBoxList.Add(filmBox);
  452. }
  453. else
  454. {
  455. Logger.Error(
  456. "Received N-ACTION request for invalid film box {0} from {1}",
  457. request.SOPInstanceUID.UID,
  458. CallingAE);
  459. return new DicomNActionResponse(request, DicomStatus.NoSuchObjectInstance);
  460. }
  461. }
  462. else
  463. {
  464. if (request.ActionTypeID != 0x0001)
  465. {
  466. Logger.Error(
  467. "Received N-ACTION request for invalid action type {0} from {1}",
  468. request.ActionTypeID,
  469. CallingAE);
  470. return new DicomNActionResponse(request, DicomStatus.NoSuchActionType);
  471. }
  472. else
  473. {
  474. Logger.Error(
  475. "Received N-ACTION request for invalid SOP class {0} from {1}",
  476. request.SOPClassUID,
  477. CallingAE);
  478. return new DicomNActionResponse(request, DicomStatus.NoSuchSOPClass);
  479. }
  480. }
  481. var printJob = new PrintJob(null, Printer, CallingAE, Logger)
  482. {
  483. SendNEventReport = _sendEventReports
  484. };
  485. printJob.StatusUpdate += OnPrintJobStatusUpdate;
  486. printJob.Print(filmBoxList);
  487. if (printJob.Error == null)
  488. {
  489. var result = new DicomDataset
  490. {
  491. new DicomSequence(
  492. DicomTag.ReferencedPrintJobSequenceRETIRED,
  493. new DicomDataset(
  494. new DicomUniqueIdentifier(DicomTag.ReferencedSOPClassUID, DicomUID.PrintJobSOPClass)),
  495. new DicomDataset(
  496. new DicomUniqueIdentifier(
  497. DicomTag.ReferencedSOPInstanceUID,
  498. printJob.SOPInstanceUID)))
  499. };
  500. var response = new DicomNActionResponse(request, DicomStatus.Success);
  501. response.Command.AddOrUpdate(DicomTag.AffectedSOPInstanceUID, request.SOPInstanceUID);
  502. response.Dataset = result;
  503. return response;
  504. }
  505. else
  506. {
  507. throw printJob.Error;
  508. }
  509. }
  510. catch (Exception ex)
  511. {
  512. Logger.Error(
  513. "Error occured during N-ACTION {0} for SOP class {1} and instance {2}",
  514. request.ActionTypeID,
  515. request.SOPClassUID.UID,
  516. request.SOPInstanceUID.UID);
  517. Logger.Error(ex.Message);
  518. return new DicomNActionResponse(request, DicomStatus.ProcessingFailure);
  519. }
  520. }
  521. }
  522. private void OnPrintJobStatusUpdate(object sender, StatusUpdateEventArgs e)
  523. {
  524. var printJob = sender as PrintJob;
  525. if (printJob.SendNEventReport)
  526. {
  527. var reportRequest = new DicomNEventReportRequest(
  528. printJob.SOPClassUID,
  529. printJob.SOPInstanceUID,
  530. e.EventTypeId);
  531. var ds = new DicomDataset
  532. {
  533. { DicomTag.ExecutionStatusInfo, e.ExecutionStatusInfo },
  534. { DicomTag.FilmSessionLabel, e.FilmSessionLabel },
  535. { DicomTag.PrinterName, e.PrinterName }
  536. };
  537. reportRequest.Dataset = ds;
  538. SendRequestAsync(reportRequest).Wait();
  539. }
  540. }
  541. #endregion
  542. public void Clean()
  543. {
  544. //delete the current active print job and film sessions
  545. lock (_synchRoot)
  546. {
  547. _filmSession = null;
  548. _printJobList.Clear();
  549. }
  550. }
  551. #region IDicomNServiceProvider Members
  552. public DicomNEventReportResponse OnNEventReportRequest(DicomNEventReportRequest request)
  553. {
  554. throw new NotImplementedException();
  555. }
  556. #endregion
  557. }
  558. }