接着上一篇:上一篇寫了安裝,這篇直接搞定批量打印,A4紙橫版豎版頁面設計,正式開始。(個人表達不怎麼好,我儘可能發圖片都是程序員一點就通)
1、界面展現
忽略界面設計醜
查看預覽界面,由於有數據就不截全屏了,盒號是我本身加的,咱們本身的業務邏輯。
3、核心代碼,批量打印(參考代碼連接,放到文章結尾處)
1 public class BillPrint : IDisposable 2 { 3 /// <summary> 4 /// 當前打印頁號 5 /// </summary> 6 static int m_currentPageIndex; 7 8 /// <summary> 9 /// RDCL轉換stream一頁對應一個stream 10 /// </summary> 11 static List<Stream> m_streams; 12 13 /// <summary> 14 /// 把report輸出成stream 15 /// </summary> 16 /// <param name="report">傳入須要Export的report</param> 17 private void Export(LocalReport report) 18 { 19 string deviceInfo = 20 "<DeviceInfo>" + 21 " <OutputFormat>EMF</OutputFormat>" + 22 //" <PageWidth>2in</PageWidth>" + 23 //" <PageHeight>20in</PageHeight>" + 24 //" <MarginTop>0in</MarginTop>" + 25 //" <MarginLeft>0in</MarginLeft>" + 26 //" <MarginRight>0in</MarginRight>" + 27 //" <MarginBottom>0in</MarginBottom>" + 28 "</DeviceInfo>"; 29 m_streams = new List<Stream>(); 30 report.Render("Image", deviceInfo, CreateStream, out Warning[] warnings); 31 foreach (Stream stream in m_streams) 32 stream.Position = 0; 33 } 34 35 /// <summary> 36 /// 建立具備指定的名稱和格式的流。 37 /// </summary> 38 private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek) 39 { 40 Stream stream = new FileStream(name + "." + fileNameExtension, 41 FileMode.Create); 42 m_streams.Add(stream); 43 return stream; 44 } 45 46 /// <summary> 47 /// 打印輸出 48 /// </summary> 49 private void PrintPage(object sender, PrintPageEventArgs ev) 50 { 51 Metafile pageImage = 52 new Metafile(m_streams[m_currentPageIndex]); 53 ev.Graphics.DrawImage(pageImage, ev.PageBounds); 54 m_currentPageIndex++; 55 ev.HasMorePages = (m_currentPageIndex < m_streams.Count); 56 } 57 /// <summary> 58 /// 設置橫版打印 59 /// </summary> 60 /// <param name="sender"></param> 61 /// <param name="e"></param> 62 void Document_QueryPageSettings(object sender, QueryPageSettingsEventArgs e) 63 { 64 e.PageSettings.Landscape = false; 65 int index = -1; 66 for (int i = 0; i < e.PageSettings.PrinterSettings.PaperSizes.Count; i++) 67 { 68 if (e.PageSettings.PrinterSettings.PaperSizes[i].PaperName == "A4") 69 { 70 index = i; 71 break; 72 } 73 } 74 if (index != -1) 75 { 76 e.PageSettings.PaperSize = e.PageSettings.PrinterSettings.PaperSizes[index]; 77 } 78 } 79 80 81 /// <summary> 82 /// 打印預處理 83 /// </summary> 84 private void Print(string printerName = null) 85 { 86 PrintDocument printDoc = new PrintDocument(); 87 if (string.IsNullOrEmpty(printerName)) 88 { 89 printerName = printDoc.PrinterSettings.PrinterName; 90 } 91 if (m_streams == null || m_streams.Count == 0) 92 return; 93 printDoc.PrinterSettings.PrinterName = printerName; 94 if (!printDoc.PrinterSettings.IsValid) 95 { 96 string msg = String.Format("Can't find printer \"{0}\".", printerName); 97 throw new Exception(msg); 98 } 99 printDoc.PrintPage += new PrintPageEventHandler(PrintPage); 100 101 //設置橫版打印 102 printDoc.QueryPageSettings += new QueryPageSettingsEventHandler(Document_QueryPageSettings); 103 104 StandardPrintController spc = new StandardPrintController(); 105 printDoc.PrintController = spc; 106 printDoc.Print(); 107 } 108 109 /// <summary> 110 /// 對外接口,啓動打印 111 /// </summary> 112 /// <param name="report"></param> 113 /// <param name="printerName">默認打印機</param> 114 public static void Run(LocalReport report, string printerName = null) 115 { 116 m_currentPageIndex = 0; 117 BillPrint billPrint = new BillPrint(); 118 billPrint.Export(report); 119 billPrint.Print(); 120 billPrint.Dispose(); 121 } 122 123 124 /// <summary> 125 /// 獲取打印機狀態 126 /// </summary> 127 /// <param name="printerName">打印機名稱</param> 128 /// <param name="status">輸出打印機狀態</param> 129 private static void GetPrinterStatus2(string printerName, ref uint status) 130 { 131 try 132 { 133 string lcPrinterName = printerName; 134 IntPtr liHandle = IntPtr.Zero; 135 if (!Win32.OpenPrinter(lcPrinterName, out liHandle, IntPtr.Zero)) 136 { 137 Console.WriteLine("print is close"); 138 return; 139 } 140 UInt32 level = 2; 141 IntPtr buffer = IntPtr.Zero; 142 Win32.GetPrinter(liHandle, level, buffer, 0, out uint sizeNeeded); 143 buffer = Marshal.AllocHGlobal((int)sizeNeeded); 144 if (!Win32.GetPrinter(liHandle, level, buffer, sizeNeeded, out sizeNeeded)) 145 { 146 Console.WriteLine(Environment.NewLine + "Fail GetPrinter:" + Marshal.GetLastWin32Error()); 147 return; 148 } 149 150 Win32.PRINTER_INFO_2 info = (Win32.PRINTER_INFO_2)Marshal.PtrToStructure(buffer, typeof(Win32.PRINTER_INFO_2)); 151 status = info.Status; 152 Marshal.FreeHGlobal(buffer); 153 Win32.ClosePrinter(liHandle); 154 } 155 catch (Exception ex) 156 { 157 throw ex; 158 } 159 } 160 161 /// <summary> 162 /// 對外接口,調去打印機信息 163 /// </summary> 164 /// <param name="printerName">打印機名稱</param> 165 /// <returns>返回打印機當前狀態</returns> 166 public static string GetPrinterStatus(string printerName) 167 { 168 uint intValue = 0; 169 PrintDocument pd = new PrintDocument(); 170 printerName = printerName == "" ? pd.PrinterSettings.PrinterName : printerName; 171 GetPrinterStatus2(printerName, ref intValue); 172 string strRet = string.Empty; 173 switch (intValue) 174 { 175 case 0: 176 strRet = "準備就緒(Ready)"; 177 break; 178 case 4194432: 179 strRet = "被打開(Lid Open)"; 180 break; 181 case 144: 182 strRet = "打印紙用完(Out of Paper)"; 183 break; 184 case 4194448: 185 strRet = "被打開而且打印紙用完(Out of Paper && Lid Open)"; 186 break; 187 case 1024: 188 strRet = "打印中(Printing)"; 189 break; 190 case 32768: 191 strRet = "初始化(Initializing)"; 192 break; 193 case 160: 194 strRet = "手工送紙(Manual Feed in Progress)"; 195 break; 196 case 4096: 197 strRet = "脫機(Offline)"; 198 break; 199 default: 200 strRet = "未知狀態(unknown state)"; 201 break; 202 } 203 return strRet; 204 } 205 206 207 public void Dispose() 208 { 209 if (m_streams != null) 210 { 211 foreach (Stream stream in m_streams) 212 stream.Close(); 213 m_streams = null; 214 } 215 } 216 } 217 218 public class Win32 219 { 220 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] 221 public static extern bool OpenPrinter(string printer, out IntPtr handle, IntPtr printerDefaults); 222 [DllImport("winspool.drv")] 223 public static extern bool ClosePrinter(IntPtr handle); 224 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] 225 public static extern bool GetPrinter(IntPtr handle, UInt32 level, IntPtr buffer, UInt32 size, out UInt32 sizeNeeded); 226 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 227 public struct PRINTER_INFO_2 228 { 229 public string pServerName; 230 public string pPrinterName; 231 public string pShareName; 232 public string pPortName; 233 public string pDriverName; 234 public string pComment; 235 public string pLocation; 236 public IntPtr pDevMode; 237 public string pSepFile; 238 public string pPrintProcessor; 239 public string pDatatype; 240 public string pParameters; 241 public IntPtr pSecurityDescriptor; 242 public UInt32 Attributes; 243 public UInt32 Priority; 244 public UInt32 DefaultPriority; 245 public UInt32 StartTime; 246 public UInt32 UntilTime; 247 public UInt32 Status; 248 public UInt32 cJobs; 249 public UInt32 AveragePPM; 250 } 251 }
代碼使用
1 using (ReportViewer rvDoc = new ReportViewer()) 2 { 3 rvDoc.LocalReport.DataSources.Add(new ReportDataSource("DataSet1", 你的數據)); 4 //注意本身的路徑,這塊我寫到配置文件,來區分測試跟線上路徑。 5 if (PublicProperty.RdlcPath == "Debug") 6 { 7 rvDoc.LocalReport.ReportPath = @"..\..\ReportForm\GTTKWenShuArchives.rdlc"; 8 } 9 else 10 { 11 rvDoc.LocalReport.ReportPath = Application.StartupPath + "\\ReportForm\\GTTKWenShuArchives.rdlc"; 12 } 13 //開始打印,第二個參數是選擇打印機名稱 14 BillPrint.Run(rvDoc.LocalReport, (string)printerList.Invoke(new obj_delegate(() => { return printerList.SelectedItem.ToString(); }))); 15 } 16 }
4、設計報表一些注意事項(能夠用差之毫釐失之千里來形容)
- A4豎版打印,標頭設計寬,長只能小於等於寬,要是大於就會出現空白頁狀況。
- A4橫版打印,標頭設計寬,長度跟豎版同樣,注意這個數字是我一點點試出來的,多一點就會出現表的列顯示不全,會跑到第二頁裏面,你們也能夠本身試試。
- 要想每一頁都顯示標題,只能把標題加入到頁眉之中,注意頁眉的底部必定要跟表重合不然到第二頁跟上邊距會跟第一頁不同,具體什麼樣本身試一下就知道了,
- 表要是想加實線,注意設計的時候,這個你們一試便知。
- 要想每一頁都顯示錶的標題部分能夠這麼設計
-
剩下的內容的字體啊間距啊,就根據本身需求本身調吧,注意設計的時候儘可能表要與兩邊重合,標題要與頂部重合,由於他默認是上下左右間距都是2CM,你要是有距離你打印出來就很差看了,這個本身試試就知道了。
5、結尾
把一些我參考的連接放出來,你們能夠自行參考。
https://blog.csdn.net/nuptsv_ice/article/details/41821611
有個批量打印代碼連接找不到了,要是找到會補上去的。
vs2017使用rdlc
寫在前面:由於公司要求作個批量打印工具,之前用Delphi+FastReport開發的,如今由於公司就剩下一個Delphi開發工程師了,還外出,因此這是就落在我身上。由於這個打印工具不須要使用人員設計,只要個模板打印就行, 我這用的工具是vs2017+winfrom+rdlc,好像FastReport收費了。
1、vs2017配置rdlc
由於vs2017默認沒有裝報表的須要自行安裝,安裝方法工具>擴展和更新>聯機>搜索rdlc默認第一個安裝便可,可能有點慢,個人安裝的很長時間,你也能夠本身去單獨下載。安裝完成後重啓vs2017就有了。
2、生成項目
默認有個嚮導,可根據本身需求添加,也能夠取消,後續本身添加。
項目結構
修改屬性
3、設計報表,生成數據
下面設計一個打印界面,上面嚮導的時候咱們把添加數據集跳過了,如今咱們自行添加數據,
這裏咱們自定義列,也能夠從數據庫獲取
而後添加數據集
到咱們winfrom界面添加報表
後臺數據綁定
點擊啓動便可看到如下界面,對文檔的字體大小均可以經過設計頁面進行設計
3、結尾
基本使用到此結束,剩下的就自行擴展了,至於批量打印功能,我這尚未申請到打印機,等後續打印機到手,進行測試以後補上。
[asp.net core 源碼分析] 01 - Session
一、Session文檔介紹
- 毋庸置疑學習.Net core最好的方法之一就是學習微軟.Net core的官方文檔;https://docs.microsoft.com/zh-cn/aspnet/core;
- .Net core Session的官方文檔 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/app-state
- .Net core Session Github源碼 https://github.com/aspnet/Session
二、Session簡單應用
2.一、在Startup類的ConfigureServices方法中添加
services.AddDistributedMemoryCache(); services.AddSession();
由於Session的服務端存儲須要緩存,因此須要引入.Net core的緩存DistributedMemoryCache;
2.二、在Startup類的Configure方法中添加
app.UseSession();
2.三、使用(存儲和獲取)
// 存儲 HttpContext.Session.Set("LoginId", System.Text.Encoding.Default.GetBytes("666")); // 獲取 HttpContext.Session.TryGetValue("LoginId", out byte[] byteLoginId); var loginId = System.Text.Encoding.Default.GetString(byteLoginId); // LoginId="666";
三、源碼分析圖
四、源碼分析
4.一、程序加載
4.1.一、在ConfigureServices中添加分佈式緩存,services.AddDistributedMemoryCache();
微軟官方建議使用AddDistributedMemoryCache,固然也可使用AddMemoryCache、AddDistributedRedisCache、AddDistributedSqlServerCache或者自定義緩存也是能夠的;
若是是分佈式系統或者SSO單點登陸,建議使用分佈式的緩存,不要使用AddMemoryCache;
緩存的官方文檔 https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/memory
4.1.二、在ConfigureServices中添加AddSession;
1 public static IServiceCollection AddSession(this IServiceCollection services) 2 { 3 if (services == null) 4 { 5 throw new ArgumentNullException(nameof(services)); 6 } 7 8 services.AddTransient<ISessionStore, DistributedSessionStore>(); 9 services.AddDataProtection(); 10 return services; 11 } 12 13 public static IServiceCollection AddSession(this IServiceCollection services, Action<SessionOptions> configure) 14 { 15 if (services == null) 16 { 17 throw new ArgumentNullException(nameof(services)); 18 } 19 20 if (configure == null) 21 { 22 throw new ArgumentNullException(nameof(configure)); 23 } 24 25 services.Configure(configure); 26 services.AddSession(); 27 28 return services; 29 }
AddSession爲IServiceCollection的擴展方法,有1個重載(傳入Session的設置,使用services.Configure(configure),加載設置);
services.AddDataProtection()注入數據加密解密DataProtection(),在加密解密SessionKey時使用;
services.AddTransient<ISessionStore, DistributedSessionStore>();注入DistributedSessionStore,其中的Create 方法用作建立Session,調用Create方法時執行new DistributedSession(); DistributedSession類中包含了對IDictionary<EncodedKey, byte[]>的增刪改查;
4.1.三、在Configure中UseSession
1 public static IApplicationBuilder UseSession(this IApplicationBuilder app) 2 { 3 if (app == null) 4 { 5 throw new ArgumentNullException(nameof(app)); 6 } 7 8 return app.UseMiddleware<SessionMiddleware>(); 9 } 10 11 12 public static IApplicationBuilder UseSession(this IApplicationBuilder app, SessionOptions options) 13 { 14 if (app == null) 15 { 16 throw new ArgumentNullException(nameof(app)); 17 } 18 if (options == null) 19 { 20 throw new ArgumentNullException(nameof(options)); 21 } 22 23 return app.UseMiddleware<SessionMiddleware>(Options.Create(options)); 24 }
UseSession爲IApplicationBuilder的擴展方法,也有1個重載,一樣也是加載Session的設置,使用Options.Create(options)結合中間件加載設置;
關於中間件能夠參考文檔 https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware
SessionMiddleware.cs爲Session的中間件;其中包含Session的核心代碼,操做MVC以前和以後的代碼都在中間件中;
4.二、SessionMiddleware.cs類解析
在SessionMiddleware中一個異步方法Invoke;主要邏輯中包含了註釋,應該很好理解;
1 /// <summary> 2 /// Invokes the logic of the middleware. 3 /// </summary> 4 /// <param name="context">The <see cref="HttpContext"/>.</param> 5 /// <returns>A <see cref="Task"/> that completes when the middleware has completed processing.</returns> 6 public async Task Invoke(HttpContext context) 7 { 8 var isNewSessionKey = false; 9 Func<bool> tryEstablishSession = ReturnTrue; 10 var cookieValue = context.Request.Cookies[_options.Cookie.Name]; 11 12 // 解密cookieValue 13 var sessionKey = CookieProtection.Unprotect(_dataProtector, cookieValue, _logger); 14 if (string.IsNullOrWhiteSpace(sessionKey) || sessionKey.Length != SessionKeyLength) 15 { 16 17 // 生成36位隨機數 18 var guidBytes = new byte[16]; 19 CryptoRandom.GetBytes(guidBytes); 20 sessionKey = new Guid(guidBytes).ToString(); 21 22 // 加密cookieValue 23 cookieValue = CookieProtection.Protect(_dataProtector, sessionKey); 24 25 // 設置Cookie 26 var establisher = new SessionEstablisher(context, cookieValue, _options); 27 tryEstablishSession = establisher.TryEstablishSession; 28 isNewSessionKey = true; 29 } 30 31 var feature = new SessionFeature(); 32 // 建立Sessin放入 HttpContext Features 33 feature.Session = _sessionStore.Create(sessionKey, _options.IdleTimeout, _options.IOTimeout, tryEstablishSession, isNewSessionKey); 34 context.Features.Set<ISessionFeature>(feature); 35 36 try 37 { 38 // 執行邏輯(MVC)之間 39 await _next(context); 40 // 執行邏輯(MVC)以後 41 } 42 finally 43 { 44 // 設置HttpContext Features爲空 45 context.Features.Set<ISessionFeature>(null); 46 47 if (feature.Session != null) 48 { 49 try 50 { 51 // Commit Session,把 IDictionary<EncodedKey, byte[]>中的值放入緩存 52 await feature.Session.CommitAsync(context.RequestAborted); 53 } 54 catch (OperationCanceledException) 55 { 56 _logger.SessionCommitCanceled(); 57 } 58 catch (Exception ex) 59 { 60 _logger.ErrorClosingTheSession(ex); 61 } 62 } 63 } 64 }
4.三、DistributedSession.cs 類解析
在SessionMiddleware Invoke方法中,能夠看到建立Session最終執行的是new DistributedSession();
此類就不作過多的介紹了,主要就是對IDictionary<EncodedKey, byte[]>增刪改查,序列化值、從緩存中Load數據和把數據放入緩存中;
代碼過多就不放置博客上,可移至github :https://github.com/aspnet/Session/blob/master/src/Microsoft.AspNetCore.Session/DistributedSession.cs
五、總結
一、在asp.net core中Session的代碼仍是比較簡單的,運用操做也比較簡單;
二、能夠清楚的理解asp.net core中Session的原理;
三、能夠學習其餘生產隨機數的方法;
四、能夠學習在中間件中怎麼運用設置(Options.Create(options)、services.Configure(configure));
五、知道了中間件的簡單運用;
六、學寫了Httpcontext Features 的簡單運用,關於 HttpContext能夠直接使用Session(HttpContext.Session)在講asp.net core http時會詳細介紹;
七、簡單知道了對於緩存的獲取和增長;
八、下一篇將分析 .net core configuration,敬請關注;
九、記得推薦評論,或者能夠留言但願分析哪部分asp.net core的源碼
SignalR
從上面的介紹能夠看出,SignalR既然是爲實時而生的,這樣就決定了其使用場所。具體適用情景有以下幾點:
- 聊天室,如在線客服系統,IM系統等
- 股票價格實時更新
- 消息的推送服務
- 遊戲中人物位置的實時推送 : 遊戲參考 https://blog.csdn.net/jaswhen/article/details/48517999
Asp.net SignalR是微軟爲實現實時通訊的一個類庫。通常狀況下,signalR會使用JavaScript的長輪詢(long polling)的方式來實現客戶端和服務器通訊,隨着Html5中WebSockets出現,SignalR也支持WebSockets通訊。另外SignalR開發的程序不只僅限制於宿主在IIS中,也能夠宿主在任何應用程序,包括控制檯,客戶端程序和Windows服務等,另外還支持Mono,這意味着它能夠實現跨平臺部署在Linux環境下。
signalR內部有兩類對象:
- Http持久鏈接(Persisten Connection)對象:用來解決長時間鏈接的功能。還能夠由客戶端主動向服務器要求數據,而服務器端不須要實現太多細節,只須要處理PersistentConnection 內所提供的五個事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 便可。
- Hub(集線器)對象:用來解決實時(realtime)信息交換的功能,服務端能夠利用URL來註冊一個或多個Hub,只要鏈接到這個Hub,就能與全部的客戶端共享發送到服務器上的信息,同時服務端能夠調用客戶端的腳本。SignalR將整個信息的交換封裝起來,客戶端和服務器都是使用JSON來溝通的,在服務端聲明的全部Hub信息,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理對象,而Proxy的內部則是將JSON轉換成對象。
SignalR將整個信息的交換封裝起來,客戶端和服務器都是使用JSON來溝通的,在服務端聲明的全部Hub信息,都會生成JavaScript輸出到客戶端,.NET則依賴Proxy來生成代理對象,而Proxy的內部則是將JSON轉換成對象。
SignalR的服務端提供了兩種實現方式,分別是PersistentConnection和Hub,這兩種方式的側重點不一樣:
PersistentConnection | Hub/生成Proxy模式 | Hub/非生成Proxy模式 | |
服務端配置 | app.Map("/messageConnection", map => |
app.Map("/messageHub", map => |
app.Map("/messageHub", map => |
引入js文件 | jquery-1.6.4.min.js jquery.signalR-2.2.0.min.js |
jquery-1.6.4.min.js jquery.signalR-2.2.0.min.js /messageHub/js 上述js文件是動態生成,其中messageHub的爲服務端定義的路徑 |
jquery-1.6.4.min.js jquery.signalR-2.2.0.min.js |
建立鏈接 | var connection = $.connection("/message"); | var connection = $.connection; | var connection = $.hubConnection(); |
開啓鏈接 | connection.start() |
connection.hub.start() |
connection.start() |
代理對象 | 無 | var proxy = connection.MessageService; MessageService是Hub的名稱 |
var proxy = connection.createHubProxy("MessageService"); MessageService是Hub的名稱 |
定義客戶端方法 | 無 | proxy.client.hello = function (message) { } |
proxy.on("hello", function (message) { console.log(message); }); |
接收消息 | connection.received(function (message) { |
經過服務器調用客戶端方法實現 |
經過服務器調用客戶端方法實現 |
發送消息 | connection.send(message); | 經過調用服務端方法實現 proxy.server.hello(message); |
經過調用服務端方法實現 proxy.invoke("hello", message); |
設置QueryString | 在建立connection時指定 var connection = $.connection("/messageConnection", { username: "qs" + username }); |
connection.hub.qs = { username: "qs" + username }; |
connection.qs = { username: "qs" + username }; |
設置Cookie | document.cookie = "username=" + username; | document.cookie = "username=" + username; | document.cookie = "username=" + username; |
設置State | 無 | proxy.state.ClientType = "HubAutoProxy"; | proxy.state.ClientType = "HubNonAutoProxy"; |
示例代碼下載
容易碰到的問題:
1.預約義的類型「Microsoft.CSharp.RuntimeBinder.Binder」未定義或未導入:https://blog.csdn.net/rztyfx/article/details/61432763
2.Owin:
Install-Package microsoft.owin.cors
Update-Package Owin -Reinstall
3.關於SignalR鏈接數量問題的記錄:https://blog.csdn.net/Andrewniu/article/details/80243120
sql for xml path用法
FOR XML PATH 有的人可能知道有的人可能不知道,其實它就是將查詢結果集以XML形式展示,有了它咱們能夠簡化咱們的查詢語句實現一些之前可能須要藉助函數活存儲過程來完成的工做。那麼以一個實例爲主.
一.FOR XML PATH 簡單介紹
那麼仍是首先來介紹一下FOR XML PATH ,假設如今有一張興趣愛好表(hobby)用來存放興趣愛好,表結構以下:
接下來咱們來看應用FOR XML PATH的查詢結果語句以下:
結果:
<hobbyID>1</hobbyID>
<hName>登山</hName>
</row>
<row>
<hobbyID>2</hobbyID>
<hName>游泳</hName>
</row>
<row>
<hobbyID>3</hobbyID>
<hName>美食</hName>
</row>
因而可知FOR XML PATH 能夠將查詢結果根據行輸出成XML各式!
那麼,如何改變XML行節點的名稱呢?代碼以下:
結果必定也可想而知了吧?沒錯原來的行節點<row> 變成了咱們在PATH後面括號()中,自定義的名稱<MyHobby>,結果以下:
<hobbyID>1</hobbyID>
<hName>登山</hName>
</MyHobby>
<MyHobby>
<hobbyID>2</hobbyID>
<hName>游泳</hName>
</MyHobby>
<MyHobby>
<hobbyID>3</hobbyID>
<hName>美食</hName>
</MyHobby>
這個時候細心的朋友必定又會問那麼列節點如何改變呢?還記的給列起別名的關鍵字AS嗎?對了就是用它!代碼以下:
那麼這個時候咱們列的節點名稱也會編程咱們自定義的名稱 <MyCode>與<MyName>結果以下:
<MyCode>1</MyCode>
<MyName>登山</MyName>
</MyHobby>
<MyHobby>
<MyCode>2</MyCode>
<MyName>游泳</MyName>
</MyHobby>
<MyHobby>
<MyCode>3</MyCode>
<MyName>美食</MyName>
</MyHobby>
噢! 既然行的節點與列的節點咱們均可以自定義,咱們是否能夠構建咱們喜歡的輸出方式呢?仍是看代碼:
沒錯咱們還能夠經過符號+號,來對字符串類型字段的輸出格式進行定義。結果以下:
那麼其餘類型的列怎麼自定義? 不要緊,咱們將它們轉換成字符串類型就行啦!例如:
好的 FOR XML PATH就基本介紹到這裏吧,更多關於FOR XML的知識請查閱幫助文檔!
接下來咱們來看一個FOR XML PATH的應用場景吧!那麼開始吧。。。。。。
二.一個應用場景與FOR XML PATH應用
首先呢!咱們在增長一張學生表,列分別爲(stuID,sName,hobby),stuID表明學生編號,sName表明學生姓名,hobby列存學生的愛好!那麼如今表結構以下:
這時,咱們的要求是查詢學生表,顯示全部學生的愛好的結果集,代碼以下:
SELECT sName,
(SELECT hobby+',' FROM student
WHERE sName=A.sName
FOR XML PATH('')) AS StuList
FROM student A
GROUP BY sName
) B
結果以下:
分析: 好的,那麼咱們來分析一下,首先看這句:
WHERE sName=A.sName
FOR XML PATH('')
這句是經過FOR XML PATH 將某一姓名如張三的愛好,顯示成格式爲:「 愛好1,愛好2,愛好3,」的格式!
那麼接着看:
SELECT sName,
(SELECT hobby+',' FROM student
WHERE sName=A.sName
FOR XML PATH('')) AS StuList
FROM student A
GROUP BY sName
) B
剩下的代碼首先是將表分組,在執行FOR XML PATH 格式化,這時當尚未執行最外層的SELECT時查詢出的結構爲:
能夠看到StuList列裏面的數據都會多出一個逗號,這時隨外層的語句:SELECT B.sName,LEFT(StuList,LEN(StuList)-1) as hobby 就是來去掉逗號,並賦予有意義的列明!
MemCahe
首先介紹下memcahce的定義:是一個分佈式的高速緩存系統,目前被許多網站使用以提高網站的訪問速度,尤爲對於一些大型的、須要頻繁訪問數據庫的網站訪問速度提高效果十分顯著。
接下來介紹下在windows下的memcache的安裝與使用:
第一步:下載memcache安裝包
連接:下載mamcache安裝包 密碼: kwt5
第二步:安裝memcache服務:
1 開啓memcache服務:首先查看本身計算機所開啓的服務----在開始菜單查詢裏輸入命令:services.msc
接下來在dos窗口安裝memcache服務-----在開始菜單查詢裏輸入cmd指令,打開dos黑窗口
接下來輸入指令來開啓memcache服務
那麼這個時候刷新下服務,就會出現memcached server
談到這個地方,有些人不明白memcache 與memcached的區別,這裏簡要說下,memecache是項目名,叫分佈式緩存系統,而memcached.exe是一個程序名,只是項目中的一個啓動服務的程序。
接下來經過telnet命令,來鏈接服務器的memcache端口,往memcache裏面添加數據,進行一些簡單操做。
telnet:是TCP/IP協議族中的一員,簡單說就是能夠經過telnet指令來鏈接指定的服務器(能夠是多臺服務器),對服務器中的內容進行操做。
首先開啓telnet本機服務----打開控制面板,選擇程序和功能,打開或關閉windows功能,在Telnet客戶端上打鉤。
下一步:經過telnet命令鏈接本地服務器的memcache端口
鏈接成功後的結果:
若是鏈接不成功,請檢查下telnet客戶端功能有沒有添加,memcache服務狀態是不是已啓動。
接下來開始玩一下memcache。
首先輸入stats,返回統計信息例如 PID(進程號)、版本號、鏈接數等
這裏面的參數參考:http://www.runoob.com/memcached/memcached-stats.html
接下來就是一些簡單的指令操做,具體的學習參考上面的連接。
學習到這裏,我相信基本的memcache使用應該會了。接下來寫了一個demo,也比較簡單。
首先須要下載memcache,net庫 下載地址:連接: 下載memcache,net庫 密碼: fsfw
引用三個dll文件:ICSharpCode.SharpZipLib.dll log4net.dll Memcached.ClientLibrary.dll
namespace MemCacheDemo { class Program { static void Main(string[] args) { string[] servers = { "127.0.0.1:11211" };// 127.0.0.1:服務器地址,11211:memcache端口號 # region 初始化池 SockIOPool pool = SockIOPool.GetInstance(); //設置服務器列表 pool.SetServers(servers); //各服務器之間負載均衡的設置比例 pool.SetWeights(new int[] { 1 }); //初始化時建立鏈接數 pool.InitConnections = 3; //最小鏈接數 pool.MinConnections = 3; //最大鏈接數 pool.MaxConnections = 5; //鏈接的最大空閒時間,下面設置爲6個小時(單位ms),超過這個設置時間,鏈接會被釋放掉 pool.MaxIdle = 1000 * 60 * 60 * 6; //socket鏈接的超時時間,下面設置表示不超時(單位ms),即一直保持連接狀態 pool.SocketConnectTimeout = 0; //通信的超時時間,下面設置爲3秒(單位ms),.Net版本沒有實現 pool.SocketTimeout = 1000 * 3; //維護線程的間隔激活時間,下面設置爲30秒(單位s),設置爲0時表示不啓用維護線程 pool.MaintenanceSleep = 30; //設置SocktIO池的故障標誌 pool.Failover = true; //是否對TCP/IP通信使用nalgle算法,.net版本沒有實現 pool.Nagle = false; //socket單次任務的最大時間(單位ms),超過這個時間socket會被強行中端掉,當前任務失敗。 pool.MaxBusy = 1000 * 10; pool.Initialize(); #endregion #region 客戶端實例 MemcachedClient Cache = new MemcachedClient(); //是否啓用壓縮數據:若是啓用了壓縮,數據壓縮長於門檻的數據將被儲存在壓縮的形式 Cache.EnableCompression = false; //壓縮設置,超過指定大小的都壓縮 //cache.CompressionThreshold = 1024 * 1024; Cache.Add("myKey", "523146");//向memcache緩存裏添加數據 #endregion pool.Shutdown();//關閉鏈接池 } } }
對上面的代碼解釋下:首先設置鏈接的服務器,及memcache端口號 接下來初始化sock線程池 實例化memcache客戶端,添加鍵值。
運行後,能夠在dos窗口中獲取myKey值。
看到這裏,相信讀者有了一點感受了。
接下來,談談爲何使用memcache可以提升用戶的訪問速度?
假設有10萬個用戶請求網站,那麼後臺程序會到數據庫裏查詢用戶數據,將查詢到的數據放入到memcache中,這裏會爲每一個用戶隨機產生一個guid用來表示key,登陸信息的數據放在value中,而後根據guid經過hash算法產生特定的哈希值用來將用戶信息按照必定的規則存儲在memcache中。這樣子,當用戶訪問主頁的時候,首先會到memcache緩存裏查詢是否有登陸信息,而不須要到數據庫裏查詢。同時由於每一個用戶信息都按照必定的規則存放在緩存中,因此到緩存裏查詢數據時,會節省時間。
寫下這篇文章主要記錄本身學習的點點滴滴,固然這篇博客裏也參考了博友們的文章和一些視頻資料。若是讀者有什麼不明白地方,或者以爲文章有錯誤,歡迎指正,謝謝。
C# 操做Excel圖形——繪製、讀取、隱藏、刪除圖形
簡介
本篇文章將介紹C# 如何處理Excel圖形相關的問題,包括如下內容要點:
1.繪製圖形
1.1 繪製圖形並添加文本到圖形
1.2 添加圖片到圖形
1.3 設置圖形陰影效果
2. 提取圖形中的文本、圖片
3. 設置圖形的顯示、隱藏
4. 刪除圖形
4.1刪除指定圖形
4.2 刪除全部圖形
所需工具
PS: 下載安裝該類庫後,注意在項目程序中添加引用Spire.Xls.dll文件(dll文件可在安裝路徑下的Bin文件夾中獲取)
注:Spire.xls能支持的圖形種類不少,常見的Office Excel中的圖形,這個類庫也都能實現,
示例代碼(供參考)
1. 繪製圖形
【C#】
using System.Drawing; using Spire.Xls; using Spire.Xls.Core; namespace Add_shapes_to_Excel { class Program { static void Main(string[] args) { //建立實例 Workbook workbook = new Workbook(); //獲取第一個工做表 Worksheet sheet = workbook.Worksheets[0]; //添加「太陽」形狀的圖形,並填充顏色 IPrstGeomShape Triangle = sheet.PrstGeomShapes.AddPrstGeomShape(2, 2, 170, 160, PrstGeomShapeType.Sun); Triangle.Fill.ForeColor = Color.Orange; Triangle.Fill.FillType = ShapeFillType.SolidColor; Triangle.Text = "IT'S A SUNNY DAY";//添加文本 //添加「禁止」標誌的圖形,並填充漸變顏色 IPrstGeomShape heart = sheet.PrstGeomShapes.AddPrstGeomShape(2, 7, 140, 140, PrstGeomShapeType.NoSmoking); heart.Fill.ForeColor = Color.Red; heart.Fill.FillType = ShapeFillType.Gradient; //添加雲朵形狀的圖形 IPrstGeomShape Cloud = sheet.PrstGeomShapes.AddPrstGeomShape(15, 2, 160, 160, PrstGeomShapeType.Cloud); //設置圖形陰影效果 Cloud.Shadow.Angle = 90; Cloud.Shadow.Distance = 10; Cloud.Shadow.Size = 100; Cloud.Shadow.Color = Color.SteelBlue; Cloud.Shadow.Blur = 30; Cloud.Shadow.Transparency = 1; Cloud.Shadow.HasCustomStyle = true; //添加五角星形狀的圖形,並加載圖片來填充圖形 IPrstGeomShape cloud = sheet.PrstGeomShapes.AddPrstGeomShape(15, 7, 160, 160, PrstGeomShapeType.Star5); cloud.Fill.CustomPicture(Image.FromFile("sm.png"), "sm.png"); cloud.Fill.FillType = ShapeFillType.Picture; //保存並打開文檔 workbook.SaveToFile("AddShapes.xlsx", ExcelVersion.Version2013); System.Diagnostics.Process.Start("AddShapes.xlsx"); } } }
圖形插入效果:
2.提取圖形中的文本和圖片
【C#】
using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Text; using Spire.Xls; using Spire.Xls.Core; namespace Extract_text_and_image_from_Excel_shape { class Program { static void Main(string[] args) { //建立實例,加載Excel工做表 Workbook workbook = new Workbook(); workbook.LoadFromFile("test.xlsx"); //獲取第一個工做表 Worksheet sheet = workbook.Worksheets[0]; //提取指定形狀中的文本內容,並將提取到的文本保存到指定文檔 IPrstGeomShape shape1 = sheet.PrstGeomShapes[0]; string s = shape1.Text; StringBuilder sb = new StringBuilder(); sb.AppendLine(s); File.WriteAllText("ExtractText.txt", sb.ToString()); System.Diagnostics.Process.Start("ExtractText.txt"); //提取指定圖形中的圖片,並保存圖片到指定文件 IPrstGeomShape shape2 = sheet.PrstGeomShapes[3]; Image image = shape2.Fill.Picture; image.Save("ShapeImage.png", ImageFormat.Png); System.Diagnostics.Process.Start("ShapeImage.png"); } } }
提取結果:
3. 設置圖形的隱藏、顯示
【C#】
using Spire.Xls; namespace HideShapes_XLS { class Program { static void Main(string[] args) { //建立實例,加載Excel文檔 Workbook workbook = new Workbook(); workbook.LoadFromFile("test.xlsx"); //獲取第一個工做表 Worksheet sheet = workbook.Worksheets[0]; //隱藏第3個圖形 sheet.PrstGeomShapes[2].Visible = false; //顯示圖形 //sheet.PrstGeomShapes[1].Visible = true; //保存並打開文檔 workbook.SaveToFile("HideShape.xlsx", ExcelVersion.Version2013); System.Diagnostics.Process.Start("HideShape.xlsx"); } } }
設置效果:
4. 刪除Excel圖形
【C#】
using Spire.Xls; namespace RemoveShapes_XLS { class Program { static void Main(string[] args) { //實例化Workbook類對象,加載Excel文件 Workbook workbook = new Workbook(); workbook.LoadFromFile("test.xlsx"); //獲取第一個工做表 Worksheet sheet = workbook.Worksheets[0]; //刪除第一個圖形 sheet.PrstGeomShapes[0].Remove(); //刪除全部圖形 //for (int i = sheet.PrstGeomShapes.Count-1; i >= 0; i--) //{ // sheet.PrstGeomShapes[i].Remove(); //} //保存並打開文件 workbook.SaveToFile("DeleteShape.xlsx", ExcelVersion.Version2013); System.Diagnostics.Process.Start("DeleteShape.xlsx"); } } }
圖形刪除效果:
以上是關於「C#操做Excel中圖形」的介紹,如需轉載,請註明出處。
ASP.NET MVC 是微軟官方提供的以MVC模式爲基礎的ASP.NET Web應用程序(Web Application)框架,它由Castle的MonoRail而來。
MVC 編程模式
MVC 是三種 ASP.NET 編程模式中的一種。
MVC 是一種使用 MVC(Model View Controller 模型-視圖-控制器)設計建立 Web 應用程序的模式。
(1)Model(模型)表示應用程序核心(好比數據庫記錄列表)。
(2)View(視圖)顯示數據(數據庫記錄)。
(3)Controller(控制器)處理輸入(寫入數據庫記錄)。
MVC 模式同時提供了對 HTML、CSS 和 JavaScript 的徹底控制。Model(模型)是應用程序中用於處理應用程序數據邏輯的部分。一般模型對象負責在數據庫中存取數據。View(視圖)是應用程序中處理數據顯示的部分。一般視圖是依據模型數據建立的。Controller(控制器)是應用程序中處理用戶交互的部分。一般控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據。
新建一個ASP.NET MVC4應用程序,結構以下圖所示:
對各個文件夾的說明:
(1)App_Data 文件夾用於存儲應用程序數據。
(2)Content 文件夾用於存放靜態文件,好比樣式表(CSS 文件)、圖標和圖像。
(3)Controllers 文件夾包含負責處理用戶輸入和相應的控制器類。
(4)Models 文件夾包含表示應用程序模型的類。模型控制並操做應用程序的數據。
(5)Views 文件夾用於存儲與應用程序的顯示相關的 HTML 文件(用戶界面)。
(6)Scripts 文件夾存儲應用程序的 JavaScript 文件。
下面就主要的Controller、Model和View作出說明。
1、控制器
一、描述
控制器(Controller)主要負責響應用戶的輸入,並在響應時修改模型(Model)。經過這種方式,控制器主要關注的是應用程序流、輸入數據的處理,以及對相關視圖(View)輸出數據的提供。
二、簡單控制器
新建一個ASP.NET MVC4應用程序,會自動生成一個HomeController和AccountController。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } } }
直接按F5運行程序便可看到index試圖中的內容,此時瀏覽器的URL爲:
http://localhost:4573,或者修改瀏覽器地址爲:
http://localhost:4573/home
http://localhost:4573/home/index
程序默認會託管在VS2013自帶的IIS中,採用的端口號爲4573。若是程序託管在MyWeb.com中,則URL應爲:
http://MyWeb.com/home/index。
三、控制器操做中的參數
前面的例子Action中返回的是字符串常量,下面就讓它們經過相應URL傳進來的參數動態地執行操做。
在這裏,咱們使用HttpUtility.HtmlEncode來預處理用戶輸入。這樣就能阻止用戶用連接向視圖中注入JavaScriptd代碼或HTML標記,好比/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。
public string SayHello(string content) { string message = HttpUtility.HtmlEncode("Hello " + content); return message; }
-
-
public string Details(int Id) { return "ID:" + Id; }
四、路由---將URL映射到動做
框架是如何知道將URL映射到一個特定的控制動做的?答案就在Global.asax文件的RegisterRoutes方法中。該方法定義了將一個URL模式映射到控制器或動做的路由。
using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace MvcApplication1 { // 注意: 有關啓用 IIS6 或 IIS7 經典模式的說明, // 請訪問 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); } } }
- 在RegisterRoutes方法上按F12,轉到該方法的定義,以下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplication1 { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
五、控制器總結
(1)不須要作任何配置,只需瀏覽到/控制器/動做URL便可;
(2)控制器是一個很是簡單的類,繼承自System.Web.Mvc.Controller類;
(3)用控制器在瀏覽器中顯示文本,沒有用到View或Model。
2、視圖
一、做用
提供用戶界面。一個控制器能夠對應多個試圖,一個視圖能夠被多個控制器使用。
在Action名上右鍵→添加試圖→View1。
二、指定視圖
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>View1</title> </head> <body> <div> <h2>@ViewBag.Message</h2> </div> </body> </html>
三、ViewData和ViewBag的區別於聯繫
在前面的例子中,使用了ViewBag的Message屬性從控制器往視圖傳遞數據,ViewData是一個特殊的字典類,能夠按標準語法進行使用:ViewData["CurrentTime"]=DateTime.Now;
這種語法也能夠用動態封裝器ViewBag:ViewBag.CurrentTime=DateTime.Now;
注意:
(1)儘管只有當要訪問的關鍵字是有效的C#標識符是,ViewBag才起做用,如在ViewData["Key With Spaces"]就不能使用ViewBag訪問,編譯不經過;
(2)動態值不能做爲一個參數傳遞給擴展方法。由於C#編譯器爲了選擇正確的擴展方法,在編譯是必須知道每一個參數真正類型。如:@Html.TextBox("name",ViewBag.Name)不會編譯經過,能夠改成:
①@Html.TextBox("name",ViewData["Name"])
②@Html.TextBox("name",(string)ViewBag.Name)
四、強類型視圖
如今須要編寫一個顯示Album實例列表的視圖。一簡單的方法就是經過ViewBag屬性把那些Album實例添加到視圖數據字典中,而後在視圖中迭代他們。
(1)首先,在Models文件夾下新建一個Album類,爲了簡單起見,只定義一個Title屬性。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication1.Models { public class Album { public string Title { get; set; } } }
- (2)控制器
public ActionResult List() { var album = new List<Album>(); for (int i = 0; i < 10; i++) { album.Add(new Album { Title = "Product " + i.ToString() }); } //1、使用ViewBag傳值 //ViewBag.Album = album; //return View("ListView"); //2、使用ViewData傳值 ViewData["Album"] = album; return View("ListView"); }
(3)視圖
在List上右鍵→添加視圖。
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @*1、使用ViewBag傳值*@ @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable <MvcApplication1.Models.Album>)) { <li>@a.Title</li> }*@ @*2、使用ViewBag傳值*@ @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> } </ul> <pre name="code" class="html"> <ul> @foreach(dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul> </div> </body> </html>
運行效果:
<ul> @foreach (dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul>
請記住,ViewData是ViewDataDictionary類型的,它有一個額外的Model屬性,能夠用來在視圖中獲取指定的模型對象。因爲在ViewData中只能傳遞一個模型對象,所以,咱們利用這一點能夠很容易的實現向視圖傳遞一個特定的類對象。
在Controller方法中,能夠經過重載的List方法中傳遞模型實例來指定模型,代碼以下:
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10; i++) { album.Add(new Album { Title="Product " + i.ToString() }); } ViewData["Album"]=album; return View("ListView",album); } @model IEnumerable<MvcApplication1.Models.Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach(dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
若是不想輸入模型類型的徹底限定類型名,可以使用using關鍵字聲明,以下所示:
@using MvcApplication1.Models @model IEnumerable<Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach (dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
對於在視圖中常用的名稱空間,一個較好的方法就是在Views目錄下的web.config文件中聲明。
<system.web.webPages.razor> <host factoryType = "System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> < pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization"/> <add namespace="System.Web.Routing" /> <add namespace="MvcApplication1.Models"/> </namespaces> </pages> </system.web.webPages.razor>
五、Razor視圖引擎
5.1 先來看一個簡單的例子。
@{ Layout = null; } @{ var items = new string[] { "one", "two", "three" }; } <!DOCTYPE html> <html> <head> <title>ListView</title> </head> <body> <div> <ul> @foreach (var item in items) { <li>@item</li> } </ul> </div> </body> </html>
5.2 Html編碼
由於在不少狀況下須要用視圖顯示用戶輸入,如博客評論等,因此老是存在着潛在的跨站腳本注入攻擊(也成XSS),值得稱讚的是,Razor表達式是Html自動編碼的,以下不會彈出一個警示框,而是直接顯示html代碼。
@{ string message = "<script>alert('haacked!');</script>"; }
然而,若是想要展現Html標籤,就要返回一個System.Web.IHtml對象的實例,Razor並不對它進行編碼。固然也能夠建立一個HtmlStringl實例或者使用Html.Raw便捷方法。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@Html.Raw(message)</span>
- 效果:
雖然這種自動的HTML編碼經過對一HTML形式顯示的用戶輸入進行編碼能有效的緩和XSS的脆弱性,可是對於在JavaScript中時遠遠不夠的。例如:
<script type="text/javascript"> $(function () { var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)'; $("#message").html(message).show('slow'); }); </script>
- 當在JavaScript中將用戶提供的值賦給變量時,要使用JavaScript字符串編碼而不只僅是HTML編碼,記住這一點是很重要的,也就是要用@Ajax.JavaScriptStringEncode方法對用戶輸入進行編碼。
5.3 佈局
Razor的佈局有助於使用應用程序中的多個視圖保持一致的外觀,可以使用佈局爲網站定義公共模板(或只是其中的一部分),公共模板包含一個或多個佔位符,應用程序中的其餘視圖爲他們提供內容。
下面看一個很是簡單的佈局,新建一個名稱爲MyLayout.cshtml的視圖,因爲要做爲公共模板,因此將其放在/Views/Shared/路徑下。
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> </body> </html>
- 其中的@RenderBody()稱爲佔位符,用來標記使用這個模板的視圖將渲染他們的主要內容的位置。
接下來新建一個視圖,將使用其做爲模板。
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p>
- 運行效果以下:
佈局可能有多個節,例以下面示例在前面的佈局基礎上添加了一個頁腳節:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer")</footer> </body> </html>
- 在不作任何改變的狀況下再次運行前面的視圖,將會拋出一個異常,提示沒有定義的Footer節。
默認狀況下,視圖必須爲佈局中定義的沒一個節提供相應的內容。更新後的View1視圖以下所示:
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p> @section Footer{ This is the <strong>footer</strong>. }
RenderSection方法有一個重載的版本,容許在佈局中指定不須要的節,能夠給required參數傳遞一個false值來標記Footer節是可選的:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer", required: false)</footer> </body> </html>
5.4 ViewStart
在前面的例子中,每個視圖都是用Layout屬性來指定它的佈局,若是多個視圖使用同一個佈局,就會產生冗餘,而且很難維護。
_ViewStart.cshtml頁面可用來消除這種冗餘,這個文件的代碼先於同目錄下任何視圖代碼的執行,這個文件也能夠遞歸地應用到子目錄下的任何視圖。
@{
Layout="~/Views/Shared/_Layout.cshtml";
}
由於這個代碼先於任何視圖執行,因此一個視圖能夠重寫Layout屬性的默認值,從而從新選擇一個不一樣的佈局。
5.4 指定部分視圖
除了返回視圖以外,操做方法也能夠經過PartialView方法以PartialResult的形式返回部分視圖。
The end
ASP.NET MVC 是微軟官方提供的以MVC模式爲基礎的ASP.NET Web應用程序(Web Application)框架,它由Castle的MonoRail而來。
MVC 編程模式
MVC 是三種 ASP.NET 編程模式中的一種。
MVC 是一種使用 MVC(Model View Controller 模型-視圖-控制器)設計建立 Web 應用程序的模式。
(1)Model(模型)表示應用程序核心(好比數據庫記錄列表)。
(2)View(視圖)顯示數據(數據庫記錄)。
(3)Controller(控制器)處理輸入(寫入數據庫記錄)。
MVC 模式同時提供了對 HTML、CSS 和 JavaScript 的徹底控制。Model(模型)是應用程序中用於處理應用程序數據邏輯的部分。一般模型對象負責在數據庫中存取數據。View(視圖)是應用程序中處理數據顯示的部分。一般視圖是依據模型數據建立的。Controller(控制器)是應用程序中處理用戶交互的部分。一般控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據。
新建一個ASP.NET MVC4應用程序,結構以下圖所示:
對各個文件夾的說明:
(1)App_Data 文件夾用於存儲應用程序數據。
(2)Content 文件夾用於存放靜態文件,好比樣式表(CSS 文件)、圖標和圖像。
(3)Controllers 文件夾包含負責處理用戶輸入和相應的控制器類。
(4)Models 文件夾包含表示應用程序模型的類。模型控制並操做應用程序的數據。
(5)Views 文件夾用於存儲與應用程序的顯示相關的 HTML 文件(用戶界面)。
(6)Scripts 文件夾存儲應用程序的 JavaScript 文件。
下面就主要的Controller、Model和View作出說明。
1、控制器
一、描述
控制器(Controller)主要負責響應用戶的輸入,並在響應時修改模型(Model)。經過這種方式,控制器主要關注的是應用程序流、輸入數據的處理,以及對相關視圖(View)輸出數據的提供。
二、簡單控制器
新建一個ASP.NET MVC4應用程序,會自動生成一個HomeController和AccountController。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } } }
直接按F5運行程序便可看到index試圖中的內容,此時瀏覽器的URL爲:
http://localhost:4573,或者修改瀏覽器地址爲:
http://localhost:4573/home
http://localhost:4573/home/index
程序默認會託管在VS2013自帶的IIS中,採用的端口號爲4573。若是程序託管在MyWeb.com中,則URL應爲:
http://MyWeb.com/home/index。
三、控制器操做中的參數
前面的例子Action中返回的是字符串常量,下面就讓它們經過相應URL傳進來的參數動態地執行操做。
在這裏,咱們使用HttpUtility.HtmlEncode來預處理用戶輸入。這樣就能阻止用戶用連接向視圖中注入JavaScriptd代碼或HTML標記,好比/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。
public string SayHello(string content) { string message = HttpUtility.HtmlEncode("Hello " + content); return message; }
public string Details(int Id) { return "ID:" + Id; }
四、路由---將URL映射到動做
框架是如何知道將URL映射到一個特定的控制動做的?答案就在Global.asax文件的RegisterRoutes方法中。該方法定義了將一個URL模式映射到控制器或動做的路由。
using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace MvcApplication1 { // 注意: 有關啓用 IIS6 或 IIS7 經典模式的說明, // 請訪問 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); } } }
在RegisterRoutes方法上按F12,轉到該方法的定義,以下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplication1 { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
五、控制器總結
(1)不須要作任何配置,只需瀏覽到/控制器/動做URL便可;
(2)控制器是一個很是簡單的類,繼承自System.Web.Mvc.Controller類;
(3)用控制器在瀏覽器中顯示文本,沒有用到View或Model。
2、視圖
一、做用
提供用戶界面。一個控制器能夠對應多個試圖,一個視圖能夠被多個控制器使用。
在Action名上右鍵→添加試圖→View1。
二、指定視圖
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>View1</title> </head> <body> <div> <h2>@ViewBag.Message</h2> </div> </body> </html>
三、ViewData和ViewBag的區別於聯繫
在前面的例子中,使用了ViewBag的Message屬性從控制器往視圖傳遞數據,ViewData是一個特殊的字典類,能夠按標準語法進行使用:ViewData["CurrentTime"]=DateTime.Now;
這種語法也能夠用動態封裝器ViewBag:ViewBag.CurrentTime=DateTime.Now;
注意:
(1)儘管只有當要訪問的關鍵字是有效的C#標識符是,ViewBag才起做用,如在ViewData["Key With Spaces"]就不能使用ViewBag訪問,編譯不經過;
(2)動態值不能做爲一個參數傳遞給擴展方法。由於C#編譯器爲了選擇正確的擴展方法,在編譯是必須知道每一個參數真正類型。如:@Html.TextBox("name",ViewBag.Name)不會編譯經過,能夠改成:
①@Html.TextBox("name",ViewData["Name"])
②@Html.TextBox("name",(string)ViewBag.Name)
四、強類型視圖
如今須要編寫一個顯示Album實例列表的視圖。一簡單的方法就是經過ViewBag屬性把那些Album實例添加到視圖數據字典中,而後在視圖中迭代他們。
(1)首先,在Models文件夾下新建一個Album類,爲了簡單起見,只定義一個Title屬性。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication1.Models { public class Album { public string Title { get; set; } } }
(2)控制器
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10 ;i++) { album.Add(new Album { Title="Product " + i.ToString() }); } //1、使用ViewBag傳值 //ViewBag.Album = album; //return View("ListView"); //2、使用ViewData傳值 ViewData["Album"] = album; return View("ListView"); }
(3)視圖
在List上右鍵→添加視圖。
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @*1、使用ViewBag傳值*@ @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> }*@ @*2、使用ViewBag傳值*@ @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> } </ul> <pre name="code" class="html"> <ul> @foreach(dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul> </div> </body> </html>
運行效果:
<ul> @foreach (dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul>
請記住,ViewData是ViewDataDictionary類型的,它有一個額外的Model屬性,能夠用來在視圖中獲取指定的模型對象。因爲在ViewData中只能傳遞一個模型對象,所以,咱們利用這一點能夠很容易的實現向視圖傳遞一個特定的類對象。
在Controller方法中,能夠經過重載的List方法中傳遞模型實例來指定模型,代碼以下:
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10;i++) { album.Add(new Album { Title="Product " + i.ToString() }); } ViewData["Album"]=album; return View("ListView",album); } @model IEnumerable<MvcApplication1.Models.Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach(dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
若是不想輸入模型類型的徹底限定類型名,可以使用using關鍵字聲明,以下所示:
@using MvcApplication1.Models @model IEnumerable<Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach (dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
對於在視圖中常用的名稱空間,一個較好的方法就是在Views目錄下的web.config文件中聲明。
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization" /> <add namespace="System.Web.Routing" /> <add namespace="MvcApplication1.Models" /> </namespaces> </pages> </system.web.webPages.razor>
五、Razor視圖引擎
5.1 先來看一個簡單的例子。
@{ Layout = null; } @{ var items = new string[] { "one", "two", "three" }; } <!DOCTYPE html> <html> <head> <title>ListView</title> </head> <body> <div> <ul> @foreach (var item in items) { <li>@item</li> } </ul> </div> </body> </html>
5.2 Html編碼
由於在不少狀況下須要用視圖顯示用戶輸入,如博客評論等,因此老是存在着潛在的跨站腳本注入攻擊(也成XSS),值得稱讚的是,Razor表達式是Html自動編碼的,以下不會彈出一個警示框,而是直接顯示html代碼。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@message</span>
然而,若是想要展現Html標籤,就要返回一個System.Web.IHtml對象的實例,Razor並不對它進行編碼。固然也能夠建立一個HtmlStringl實例或者使用Html.Raw便捷方法。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@Html.Raw(message)</span>
- 效果:
雖然這種自動的HTML編碼經過對一HTML形式顯示的用戶輸入進行編碼能有效的緩和XSS的脆弱性,可是對於在JavaScript中時遠遠不夠的。例如:
<script type="text/javascript"> $(function() { var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)'; $("#message").html(message).show('slow'); }); </script>
當在JavaScript中將用戶提供的值賦給變量時,要使用JavaScript字符串編碼而不只僅是HTML編碼,記住這一點是很重要的,也就是要用@Ajax.JavaScriptStringEncode方法對用戶輸入進行編碼。
5.3 佈局
Razor的佈局有助於使用應用程序中的多個視圖保持一致的外觀,可以使用佈局爲網站定義公共模板(或只是其中的一部分),公共模板包含一個或多個佔位符,應用程序中的其餘視圖爲他們提供內容。
下面看一個很是簡單的佈局,新建一個名稱爲MyLayout.cshtml的視圖,因爲要做爲公共模板,因此將其放在/Views/Shared/路徑下。
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> </body> </html>
- 其中的@RenderBody()稱爲佔位符,用來標記使用這個模板的視圖將渲染他們的主要內容的位置。
接下來新建一個視圖,將使用其做爲模板。
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p>
佈局可能有多個節,例以下面示例在前面的佈局基礎上添加了一個頁腳節:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer")</footer> </body> </html>
- 在不作任何改變的狀況下再次運行前面的視圖,將會拋出一個異常,提示沒有定義的Footer節。
默認狀況下,視圖必須爲佈局中定義的沒一個節提供相應的內容。更新後的View1視圖以下所示:
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p> @section Footer{ This is the <strong>footer</strong> }
RenderSection方法有一個重載的版本,容許在佈局中指定不須要的節,能夠給required參數傳遞一個false值來標記Footer節是可選的:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer", required: false)</footer> </body> </html>
5.4 ViewStart
在前面的例子中,每個視圖都是用Layout屬性來指定它的佈局,若是多個視圖使用同一個佈局,就會產生冗餘,而且很難維護。
_ViewStart.cshtml頁面可用來消除這種冗餘,這個文件的代碼先於同目錄下任何視圖代碼的執行,這個文件也能夠遞歸地應用到子目錄下的任何視圖。
@{
Layout="~/Views/Shared/_Layout.cshtml";
}
由於這個代碼先於任何視圖執行,因此一個視圖能夠重寫Layout屬性的默認值,從而從新選擇一個不一樣的佈局。
5.4 指定部分視圖
除了返回視圖以外,操做方法也能夠經過PartialView方法以PartialResult的形式返回部分視圖。
The end
IOC,DIP,DI,IoC容器
Posted on 2018-07-30 17:34 一個老年人 閱讀(58) 評論(0) 編輯 收藏定義
IOC(Inversion of Control 控制反轉),DIP(Dependency Inverson Principle 依懶倒置)都屬於設計程序時指導原則,並無具體的實現。比較經常使用的五大原則SOLID(SRP單一職責、OCP開閉原則、LSP里氏轉換原則、IOC、DIP)
DI(Dependency Injection 依懶注入)屬於模式,提供了一種具體的處理程序中對應狀況的實現
IoC容器 屬於一種框架 例如
我只會autofac,屬於菜鳥,歡迎交流
IoC原則:反轉控制(通常與DIP一塊兒使用)
用代碼演示一下
public class A { public void Task() { var b=new B(); b.DoSomeThing(); } } public class B { public void DoSomeThing() { } }
上面的代碼,
類A建立和管理類B的對象的生命週期。它控制依賴類對象的建立和生命週期。
IoC原則建議反轉控制,意味着將控制內容分離到另外一個類。換句話說,將依賴關係建立控件從A類反轉到另外一個類,以下所示。
public class A { public void Task() { var b=Factory.GetB(); b.DoSomeThing(); } } public class B { public void DoSomeThing() { } }
A類不直接建立B類,而是經過一個工廠建立。咱們就實現了控制反轉
DIP原則:高級模塊不該該依懶低級模塊,二者都應該依懶抽象;抽象不該該依懶具體,具體應該依懶抽象