主頁 > .NET開發 > 基于Win服務的標簽列印(模板套打)[轉]

基于Win服務的標簽列印(模板套打)[轉]

2021-06-26 06:03:25 .NET開發

最近做了幾個專案,都有在產品貼標的需求

基本就是有個證卡類列印機,然后把產品的資訊列印在標簽上,

然后通過機器人把標簽貼到產品上面

標簽資訊包括文本,二維碼,條形碼之類的,要根據對應的資料生成二維碼,條形碼,

列印標簽的需求接到手后,開始了我的填坑之旅,

 

列印3.0源代碼:https://github.com/zeqp/ZEQP.Print

 

列印1.0

第一個專案開始,因為原來沒有研究過列印,所以在Bing上查了一下.Net列印機關的資料

發現基本上都是基于.net的
System.Drawing.Printing.PrintDocument
這個類來做自定義列印

大家都用這個做列印,我想按理也沒有問題,

所以開始了我的代碼,

PrintDocument去做列印,無非就是設定好列印機名稱,
DefaultPageSettings.PrinterSettings.PrinterName
列印份數
DefaultPageSettings.PrinterSettings.Copies
紙張方向
DefaultPageSettings.Landscape
然后列印的具體的資訊就是事件PrintPage寫進去
然后呼叫
Graphics.DrawString,Graphics.DrawImage來寫入具體的文本與圖片
Graphics.Draw的時候要指定字體,顏色,位置等資料
我把這些做成配置資料,
然后1.0版本就成了,

 

 


下圖為位置的組態檔

 

 

  代碼一寫完,用VS除錯的時候,跑得飛起,、

所有的字體,要列印資料的位置也通過組態檔可以動態的調整,感徑訓算完美,
但是現實很骨感,馬上就拍拍打臉了


PrintDocument類只能以WinForm的方式運行,不能以服務的方式運行,
具體可以參考:https://docs.microsoft.com/zh-cn/dotnet/api/system.drawing.printing?redirectedfrom=MSDN&view=netframework-4.8

 

 

 幸好客戶方面沒有什么要求,而且生產的時候會有一臺專門的上位機可以做這個事,所以做了一個無界面的WinForm,在電腦啟動的時候運行

從而解決了不能以服務的方式運行的問題,

 

列印2.0

做完列印1.0后,又接到了一個專案,又是有列印相關的功能,自然又分配到我這里來了,

但是對于上一個版本的列印,不能做為服務運行,做為自己寫的一個程式,居然有這么大的瑕疵,總感覺心里不爽

想去解決這個問題,但是在Bing上找到.Net的所有列印都是這樣做的,也找不到什么更好的方法,

只到問了很多相關的相關人士,最后給了我一個第三方的商業解決方案BarTender
相關參考:https://www.bartendersoftware.com/
這個有自己的模板編輯器,

 

 

 

有自己的SDK,有編輯器,功能也非學強大,不愧是商業列印解決方案,

根據他的SDK,同時安裝了相關程式,寫下幾句列印代碼,一個基于Win服務的列印出來了

 

 

 于是,列印2.0出來了,

 

列印3.0
但是對于一個基于第三方的商業列印方案,所有功能都是很強大,實作也簡單,

就是對于一般公司的小專案,掙的錢還不夠買這個商業套件的License

而且對于一個只會使用別人家的SDK的程式,不是一個有靈魂的程式,

因為你都不知道人家背后是怎么實作的,原理是什么都不知道,

對于我,雖然能把這個專案用BarTender完成,但是總是對這個列印方案不是很滿意,

因為我只在這個上面加了一層殼,不知道后面做了什么,

所以我一直想自己開發一個可以基于Win服務運行的列印程式,最好也要有自己的模板編輯器,

只到有一天,無意找到一篇文章

https://docs.aspose.com/display/wordsnet/Print+a+Document

他這里也解釋了有關基于服務的列印有關的問題不能解決,

并且他們已經找到了對應的解決方案,基于他的解決方案,寫了對應一個列印幫助類,

這個是基于Windows的XPS檔案API列印,

XPS是在Win 7后就是windows支持的列印檔案型別 類比PDF

基本 XpsPrint API   的相關說明

同時基本他的XPS列印幫助類,我做了測驗,可以完美的在Windows服務里面運行關列印,

  1 namespace ZEQP.Print.Framework
  2 {
  3     /// <summary>
  4     /// A utility class that converts a document to XPS using Aspose.Words and then sends to the XpsPrint API.
  5     /// </summary>
  6     public class XpsPrintHelper
  7     {
  8         /// <summary>
  9         /// No ctor.
 10         /// </summary>
 11         private XpsPrintHelper()
 12         {
 13         }
 14 
 15         // ExStart:XpsPrint_PrintDocument       
 16         // ExSummary:Convert an Aspose.Words document into an XPS stream and print.
 17         /// <summary>
 18         /// Sends an Aspose.Words document to a printer using the XpsPrint API.
 19         /// </summary>
 20         /// <param name="document"></param>
 21         /// <param name="printerName"></param>
 22         /// <param name="jobName">Job name. Can be null.</param>
 23         /// <param name="isWait">True to wait for the job to complete. False to return immediately after submitting the job.</param>
 24         /// <exception cref="Exception">Thrown if any error occurs.</exception>
 25         public static void Print(string xpsFile, string printerName, string jobName, bool isWait)
 26         {
 27             Console.WriteLine("Print");
 28             if (!File.Exists(xpsFile))
 29                 throw new ArgumentNullException("xpsFile");
 30             using (var stream = File.OpenRead(xpsFile))
 31             {
 32                 Print(stream, printerName, jobName, isWait);
 33             }
 34             //// Use Aspose.Words to convert the document to XPS and store in a memory stream.
 35             //File.OpenRead
 36             //MemoryStream stream = new MemoryStream();
 37 
 38             //stream.Position = 0;
 39             //Console.WriteLine("Saved as Xps");
 40             //Print(stream, printerName, jobName, isWait);
 41             Console.WriteLine("After Print");
 42         }
 43         // ExEnd:XpsPrint_PrintDocument
 44         // ExStart:XpsPrint_PrintStream        
 45         // ExSummary:Prints an XPS document using the XpsPrint API.
 46         /// <summary>
 47         /// Sends a stream that contains a document in the XPS format to a printer using the XpsPrint API.
 48         /// Has no dependency on Aspose.Words, can be used in any project.
 49         /// </summary>
 50         /// <param name="stream"></param>
 51         /// <param name="printerName"></param>
 52         /// <param name="jobName">Job name. Can be null.</param>
 53         /// <param name="isWait">True to wait for the job to complete. False to return immediately after submitting the job.</param>
 54         /// <exception cref="Exception">Thrown if any error occurs.</exception>
 55         public static void Print(Stream stream, string printerName, string jobName, bool isWait)
 56         {
 57             if (stream == null)
 58                 throw new ArgumentNullException("stream");
 59             if (printerName == null)
 60                 throw new ArgumentNullException("printerName");
 61 
 62             // Create an event that we will wait on until the job is complete.
 63             IntPtr completionEvent = CreateEvent(IntPtr.Zero, true, false, null);
 64             if (completionEvent == IntPtr.Zero)
 65                 throw new Win32Exception();
 66 
 67             //            try
 68             //            {
 69             IXpsPrintJob job;
 70             IXpsPrintJobStream jobStream;
 71             Console.WriteLine("StartJob");
 72             StartJob(printerName, jobName, completionEvent, out job, out jobStream);
 73             Console.WriteLine("Done StartJob");
 74             Console.WriteLine("Start CopyJob");
 75             CopyJob(stream, job, jobStream);
 76             Console.WriteLine("End CopyJob");
 77 
 78             Console.WriteLine("Start Wait");
 79             if (isWait)
 80             {
 81                 WaitForJob(completionEvent);
 82                 CheckJobStatus(job);
 83             }
 84             Console.WriteLine("End Wait");
 85             /*            }
 86                         finally
 87                         {
 88                             if (completionEvent != IntPtr.Zero)
 89                                 CloseHandle(completionEvent);
 90                         }
 91             */
 92             if (completionEvent != IntPtr.Zero)
 93                 CloseHandle(completionEvent);
 94             Console.WriteLine("Close Handle");
 95         }
 96         // ExEnd:XpsPrint_PrintStream
 97 
 98         private static void StartJob(string printerName, string jobName, IntPtr completionEvent, out IXpsPrintJob job, out IXpsPrintJobStream jobStream)
 99         {
100             int result = StartXpsPrintJob(printerName, jobName, null, IntPtr.Zero, completionEvent,
101                 null, 0, out job, out jobStream, IntPtr.Zero);
102             if (result != 0)
103                 throw new Win32Exception(result);
104         }
105 
106         private static void CopyJob(Stream stream, IXpsPrintJob job, IXpsPrintJobStream jobStream)
107         {
108 
109             //            try
110             //            {
111             byte[] buff = new byte[4096];
112             while (true)
113             {
114                 uint read = (uint)stream.Read(buff, 0, buff.Length);
115                 if (read == 0)
116                     break;
117 
118                 uint written;
119                 jobStream.Write(buff, read, out written);
120 
121                 if (read != written)
122                     throw new Exception("Failed to copy data to the print job stream.");
123             }
124 
125             // Indicate that the entire document has been copied.
126             jobStream.Close();
127             //            }
128             //            catch (Exception)
129             //            {
130             //                // Cancel the job if we had any trouble submitting it.
131             //                job.Cancel();
132             //                throw;
133             //            }
134         }
135 
136         private static void WaitForJob(IntPtr completionEvent)
137         {
138             const int INFINITE = -1;
139             switch (WaitForSingleObject(completionEvent, INFINITE))
140             {
141                 case WAIT_RESULT.WAIT_OBJECT_0:
142                     // Expected result, do nothing.
143                     break;
144                 case WAIT_RESULT.WAIT_FAILED:
145                     throw new Win32Exception();
146                 default:
147                     throw new Exception("Unexpected result when waiting for the print job.");
148             }
149         }
150 
151         private static void CheckJobStatus(IXpsPrintJob job)
152         {
153             XPS_JOB_STATUS jobStatus;
154             job.GetJobStatus(out jobStatus);
155             switch (jobStatus.completion)
156             {
157                 case XPS_JOB_COMPLETION.XPS_JOB_COMPLETED:
158                     // Expected result, do nothing.
159                     break;
160                 case XPS_JOB_COMPLETION.XPS_JOB_FAILED:
161                     throw new Win32Exception(jobStatus.jobStatus);
162                 default:
163                     throw new Exception("Unexpected print job status.");
164             }
165         }
166 
167         [DllImport("XpsPrint.dll", EntryPoint = "StartXpsPrintJob")]
168         private static extern int StartXpsPrintJob(
169             [MarshalAs(UnmanagedType.LPWStr)] String printerName,
170             [MarshalAs(UnmanagedType.LPWStr)] String jobName,
171             [MarshalAs(UnmanagedType.LPWStr)] String outputFileName,
172             IntPtr progressEvent,   // HANDLE
173             IntPtr completionEvent, // HANDLE
174             [MarshalAs(UnmanagedType.LPArray)] byte[] printablePagesOn,
175             UInt32 printablePagesOnCount,
176             out IXpsPrintJob xpsPrintJob,
177             out IXpsPrintJobStream documentStream,
178             IntPtr printTicketStream);  // This is actually "out IXpsPrintJobStream", but we don't use it and just want to pass null, hence IntPtr.
179 
180         [DllImport("Kernel32.dll", SetLastError = true)]
181         private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
182 
183         [DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
184         private static extern WAIT_RESULT WaitForSingleObject(IntPtr handle, Int32 milliseconds);
185 
186         [DllImport("Kernel32.dll", SetLastError = true)]
187         [return: MarshalAs(UnmanagedType.Bool)]
188         private static extern bool CloseHandle(IntPtr hObject);
189     }
190 
191     /// <summary>
192     /// This interface definition is HACKED.
193     /// 
194     /// It appears that the IID for IXpsPrintJobStream specified in XpsPrint.h as 
195     /// MIDL_INTERFACE("7a77dc5f-45d6-4dff-9307-d8cb846347ca") is not correct and the RCW cannot return it.
196     /// But the returned object returns the parent ISequentialStream inteface successfully.
197     /// 
198     /// So the hack is that we obtain the ISequentialStream interface but work with it as 
199     /// with the IXpsPrintJobStream interface. 
200     /// </summary>
201     [Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D")]  // This is IID of ISequenatialSteam.
202     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
203     interface IXpsPrintJobStream
204     {
205         // ISequentualStream methods.
206         void Read([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbRead);
207         void Write([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbWritten);
208         // IXpsPrintJobStream methods.
209         void Close();
210     }
211 
212     [Guid("5ab89b06-8194-425f-ab3b-d7a96e350161")]
213     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
214     interface IXpsPrintJob
215     {
216         void Cancel();
217         void GetJobStatus(out XPS_JOB_STATUS jobStatus);
218     }
219 
220     [StructLayout(LayoutKind.Sequential)]
221     struct XPS_JOB_STATUS
222     {
223         public UInt32 jobId;
224         public Int32 currentDocument;
225         public Int32 currentPage;
226         public Int32 currentPageTotal;
227         public XPS_JOB_COMPLETION completion;
228         public Int32 jobStatus; // UInt32
229     };
230 
231     enum XPS_JOB_COMPLETION
232     {
233         XPS_JOB_IN_PROGRESS = 0,
234         XPS_JOB_COMPLETED = 1,
235         XPS_JOB_CANCELLED = 2,
236         XPS_JOB_FAILED = 3
237     }
238 
239     enum WAIT_RESULT
240     {
241         WAIT_OBJECT_0 = 0,
242         WAIT_ABANDONED = 0x80,
243         WAIT_TIMEOUT = 0x102,
244         WAIT_FAILED = -1 // 0xFFFFFFFF
245     }
246 }
XpsPrintHelper

到此,基于windows服務的列印已經解決,

就只有模板編輯器的事情了,

對于原來做過基于Word的郵件合并域的經驗,自己開發一個編輯器來說工程量有點大

所以選擇了一個現有的,功能又強大的檔案編輯器,Word來做為我的標簽編輯器了,

Word可以完美的解決紙張,格式,位置等問題,只是在對應的地方用“文本域”來做占位符

然后用自定義的資料填充就可以了,

下圖為Word模板編輯

 

 編輯占位符(域)

 

 

這樣的話,一個模板就出來了

如果是圖片的話,就在域名前加Image:

如果是表格的話,在表格的開始加上TableStart:表名
在表格的未尾加上TableEnd:表名

 

協議的話,走的是所有語言都支持的http,對于以后開發SDK也方便

對于上面的模板,只要發送這樣的請球POST

對于Get請求

 

然后列印出來的效果

到此,列印3.0已經完成,

關鍵代碼
根據請求資料生成列印物體

 1 private PrintModel GetPrintModel(HttpListenerRequest request)
 2         {
 3             var result = new PrintModel();
 4             result.PrintName = ConfigurationManager.AppSettings["PrintName"];
 5             result.Template = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", "Default.docx");
 6             result.Action = PrintActionType.Print;
 7 
 8             var query = request.Url.Query;
 9             var dicQuery = this.ToNameValueDictionary(query);
10             if (dicQuery.ContainsKey("PrintName")) result.PrintName = dicQuery["PrintName"];
11             if (dicQuery.ContainsKey("Copies")) result.Copies = int.Parse(dicQuery["Copies"]);
12             if (dicQuery.ContainsKey("Template"))
13             {
14                 var tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", dicQuery["Template"]);
15                 if (File.Exists(tempPath))
16                     result.Template = tempPath;
17             }
18             if (dicQuery.ContainsKey("Action")) result.Action = (PrintActionType)Enum.Parse(typeof(PrintActionType), dicQuery["Action"]);
19 
20             foreach (var item in dicQuery)
21             {
22                 if (item.Key.StartsWith("Image:"))
23                 {
24                     var keyName = item.Key.Replace("Image:", "");
25                     if (result.ImageContent.ContainsKey(keyName)) continue;
26                     var imageModel = item.Value.ToObject<ImageContentModel>();
27                     result.ImageContent.Add(keyName, imageModel);
28                     continue;
29                 }
30                 if (item.Key.StartsWith("Table:"))
31                 {
32                     var keyName = item.Key.Replace("Table:", "");
33                     if (result.TableContent.ContainsKey(keyName)) continue;
34                     var table = item.Value.ToObject<DataTable>();
35                     table.TableName = keyName;
36                     result.TableContent.Add(keyName, table);
37                     continue;
38                 }
39                 if (result.FieldCotent.ContainsKey(item.Key)) continue;
40                 result.FieldCotent.Add(item.Key, item.Value);
41             }
42 
43             if (request.HttpMethod.Equals("POST", StringComparison.CurrentCultureIgnoreCase))
44             {
45                 var body = request.InputStream;
46                 var encoding = Encoding.UTF8;
47                 var reader = new StreamReader(body, encoding);
48                 var bodyContent = reader.ReadToEnd();
49                 var bodyModel = bodyContent.ToObject<Dictionary<string, object>>();
50                 foreach (var item in bodyModel)
51                 {
52                     if (item.Key.StartsWith("Image:"))
53                     {
54                         var imageModel = item.Value.ToJson().ToObject<ImageContentModel>();
55                         var keyName = item.Key.Replace("Image:", "");
56                         if (result.ImageContent.ContainsKey(keyName))
57                             result.ImageContent[keyName] = imageModel;
58                         else
59                             result.ImageContent.Add(keyName, imageModel);
60                         continue;
61                     }
62                     if (item.Key.StartsWith("Table:"))
63                     {
64                         var table = item.Value.ToJson().ToObject<DataTable>();
65                         var keyName = item.Key.Replace("Table:", "");
66                         table.TableName = keyName;
67                         if (result.TableContent.ContainsKey(keyName))
68                             result.TableContent[keyName] = table;
69                         else
70                             result.TableContent.Add(keyName, table);
71                         continue;
72                     }
73                     if (result.FieldCotent.ContainsKey(item.Key))
74                         result.FieldCotent[item.Key] = HttpUtility.UrlDecode(item.Value.ToString());
75                     else
76                         result.FieldCotent.Add(item.Key, HttpUtility.UrlDecode(item.Value.ToString()));
77                 }
78             }
79             return result;
80         }
GetPrintModel

 

檔案郵件合并域

  1 public class MergeDocument : IDisposable
  2     {
  3         public PrintModel Model { get; set; }
  4         public Document Doc { get; set; }
  5         private PrintFieldMergingCallback FieldCallback { get; set; }
  6         public MergeDocument(PrintModel model)
  7         {
  8             this.Model = model;
  9             this.Doc = new Document(model.Template);
 10             this.FieldCallback = new PrintFieldMergingCallback(this.Model);
 11             this.Doc.MailMerge.FieldMergingCallback = this.FieldCallback;
 12         }
 13         public Stream MergeToStream()
 14         {
 15             if (this.Model.FieldCotent.Count > 0)
 16                 this.Doc.MailMerge.Execute(this.Model.FieldCotent.Keys.ToArray(), this.Model.FieldCotent.Values.ToArray());
 17             if (this.Model.ImageContent.Count > 0)
 18             {
 19                 this.Doc.MailMerge.Execute(this.Model.ImageContent.Keys.ToArray(), this.Model.ImageContent.Values.Select(s => s.Value).ToArray());
 20             };
 21             if (this.Model.TableContent.Count > 0)
 22             {
 23                 foreach (var item in this.Model.TableContent)
 24                 {
 25                     var table = item.Value;
 26                     table.TableName = item.Key;
 27                     this.Doc.MailMerge.ExecuteWithRegions(table);
 28                 }
 29             }
 30             this.Doc.UpdateFields();
 31 
 32             var fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PrintDoc", $"{DateTime.Now.ToString("yyMMddHHmmssfff")}.docx");
 33             var ms = new MemoryStream();
 34             this.Doc.Save(ms, SaveFormat.Xps);
 35             return ms;
 36         }
 37 
 38         public void Dispose()
 39         {
 40             this.FieldCallback.Dispose();
 41         }
 42 
 43         private class PrintFieldMergingCallback : IFieldMergingCallback, IDisposable
 44         {
 45             public HttpClient Client { get; set; }
 46             public PrintModel Model { get; set; }
 47             public PrintFieldMergingCallback(PrintModel model)
 48             {
 49                 this.Model = model;
 50                 this.Client = new HttpClient();
 51             }
 52             public void FieldMerging(FieldMergingArgs args)
 53             {
 54             }
 55 
 56             public void ImageFieldMerging(ImageFieldMergingArgs field)
 57             {
 58                 var fieldName = field.FieldName;
 59                 if (!this.Model.ImageContent.ContainsKey(fieldName)) return;
 60                 var imageModel = this.Model.ImageContent[fieldName];
 61                 switch (imageModel.Type)
 62                 {
 63                     case ImageType.Local:
 64                         {
 65                             field.Image = Image.FromFile(imageModel.Value);
 66                             field.ImageWidth = new MergeFieldImageDimension(imageModel.Width);
 67                             field.ImageHeight = new MergeFieldImageDimension(imageModel.Height);
 68                         };
 69                         break;
 70                     case ImageType.Network:
 71                         {
 72                             var imageStream = this.Client.GetStreamAsync(imageModel.Value).Result;
 73                             var ms = new MemoryStream();
 74                             imageStream.CopyTo(ms);
 75                             ms.Position = 0;
 76                             field.ImageStream = ms;
 77                             field.ImageWidth = new MergeFieldImageDimension(imageModel.Width);
 78                             field.ImageHeight = new MergeFieldImageDimension(imageModel.Height);
 79                         }; break;
 80                     case ImageType.BarCode:
 81                         {
 82                             var barImage = this.GenerateImage(BarcodeFormat.CODE_128, imageModel.Value, imageModel.Width, imageModel.Height);
 83                             field.Image = barImage;
 84                         }; break;
 85                     case ImageType.QRCode:
 86                         {
 87                             var qrImage = this.GenerateImage(BarcodeFormat.QR_CODE, imageModel.Value, imageModel.Width, imageModel.Height);
 88                             field.Image = qrImage;
 89                         }; break;
 90                     default: break;
 91                 }
 92             }
 93             private Bitmap GenerateImage(BarcodeFormat format, string code, int width, int height)
 94             {
 95                 var writer = new BarcodeWriter();
 96                 writer.Format = format;
 97                 EncodingOptions options = new EncodingOptions()
 98                 {
 99                     Width = width,
100                     Height = height,
101                     Margin = 2,
102                     PureBarcode = false
103                 };
104                 writer.Options = options;
105                 if (format == BarcodeFormat.QR_CODE)
106                 {
107                     var qrOption = new QrCodeEncodingOptions()
108                     {
109                         DisableECI = true,
110                         CharacterSet = "UTF-8",
111                         Width = width,
112                         Height = height,
113                         Margin = 2
114                     };
115                     writer.Options = qrOption;
116                 }
117                 var codeimg = writer.Write(code);
118                 return codeimg;
119             }
120 
121             public void Dispose()
122             {
123                 this.Client.Dispose();
124             }
125         }
126     }
MergeDocument

 

 

 

 

 

 

 

 注:轉自https://www.cnblogs.com/liuju150/p/Service_Print_Template_Solution.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/288402.html

標籤:.NET技术

上一篇:Win32Api -- 使應用Always on top的幾種方法

下一篇:WPF -- 點擊空白處隱藏View

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more