整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          ASP.NET MVC知識盤點:驗證、授權與安全

          ASP.NET MVC知識盤點:驗證、授權與安全

          驗證

          一般采用表單驗證完成登陸驗證,建議結合SSL使用。為限制控制器只能執行HTTPS,使用RequireHttpsAttribute

          2 授權

          對賬戶的權限的控制可以通過在控制器或控制器操作上加AuthorizeAttribute 屬性。

          擴展授權過濾器

          擴展授權過濾器可以定義繼承自AuthorizeAttribute的類,也可以定義同時繼承自FilterAttribute, IAuthorizationFilter接口的類。

          擴展AuthorizeAttribute

           [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited=true, AllowMultiple=true)]
           public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
           {
           public AuthorizeAttribute(); 
           
           // 獲取或設置有權訪問控制器或操作方法的用戶角色
           public string Roles { get; set; }
           
           //獲取此特性的唯一標識符。
           public override object TypeId { get; }
           
           // 獲取或設置有權訪問控制器或操作方法的用戶。
           public string Users { get; set; }
           
           //重寫時,提供一個入口點用于進行自定義授權檢查
           // 返回結果: 
           // 如果用戶已經過授權,則為 true;否則為 false。
           // 異常: 
           // System.ArgumentNullException:
           // httpContext 參數為 null。
           protected virtual bool AuthorizeCore(HttpContextBase httpContext);
           
           //處理未能授權的 HTTP 請求。
           protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
           
           //在過程請求授權時調用。
           // 異常: 
           // System.ArgumentNullException:
           // filterContext 參數為 null。
           public virtual void OnAuthorization(AuthorizationContext filterContext);
           
           //
           // 返回結果: 
           // 對驗證狀態的引用。
           //
           // 異常: 
           // System.ArgumentNullException:
           // httpContext 參數為 null。
           protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
          	}
          

          AuthorizeAttribute提供了三個可重新的虛方法AuthorizeCore,HandleUnauthorizedRequest,OnAuthorization,那么在執行授權動作的過程中他們是如何被調用的呢?

          看下源碼的OnAuthorization方法,發現在這個方法中先調用AuthorizeCore,然后調用HandleUnauthorizedRequest被調用了。

          public virtual void OnAuthorization(AuthorizationContext filterContext)
           {
           if (filterContext==null)
           {
           throw new ArgumentNullException("filterContext");
           }
          //如果子操作的緩存處于活動狀態,那么就拋出異常
           if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
           {
           throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
           }
          

          //判斷控制器或控制器操作是否允許匿名訪問,如果可以就return

           bool skipAuthorization=filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);
           
           if (skipAuthorization)
           {
           return;
           }
          //進行權限驗證
           if (AuthorizeCore(filterContext.HttpContext))
           {
           HttpCachePolicyBase cachePolicy=filterContext.HttpContext.Response.Cache;
           cachePolicy.SetProxyMaxAge(new TimeSpan(0));
           cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
           }
           else
           {//處理未通過權限驗證的情形
           HandleUnauthorizedRequest(filterContext);
           }
           }
          

          綜合以上分析,擴展AuthorizeAttribute要注意:

          1)在子類AuthorizeCore中,調用父類的AuthorizeCore方法

          base.OnAuthorization(filterContext);

          2)在子類的AuthorizeCore方法中驗證用戶的權限。

          3)通過子類的構造函數傳入用戶的權限值

          代碼示例如下:

          public class CustomAuthorizeAttribute : AuthorizeAttribute
           {
           private UserRole role;
           public CustomAuthorizeAttribute(UserRole role)
           {
           this.role=role;
           }
           protected override bool AuthorizeCore(HttpContextBase httpContext)
           {
           bool ret=false;
           
           //獲得用戶信息(從本地Session或分布式緩存中獲取)
           var userInfo=......
           if(userInfo==null)
           {
           //信息為null,一般認為登陸超時或沒有登陸
           }
           
           if(userInfo.Role==UserRole.Org)
           {
           ret=true;
           }
           else
           {
           //提示無權限
           }
           
           return ret;
           }
           protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
           {
           if (filterContext==null)
           {
           throw new ArgumentNullException("filterContext");
           }
           
           if (filterContext.HttpContext.Request.IsAjaxRequest())
           {//針對ajax請求進行處理
           
           }
           else
           {//非aiax進行處理
           
           //跳轉到指定頁面
           string strUrl=......;
           filterContext.Result=new RedirectResult(strUrl);
           }
           }
           public override void OnAuthorization(AuthorizationContext filterContext)
           {
           base.OnAuthorization(filterContext);
           }
           }
           public enum UserRole
           {
           Org=1,
           Vip=2,
           Guest=3
          	}
          

          3 安全

          總的原則:

          • 所有層或各個子系統各自負責好自己的安全。
          • 任何用戶數據和來自其他系統的數據都要經過檢驗。
          • 在滿足需求的情況下,盡量縮小賬戶的權限。
          • 減少暴露的操作數量和操作參數。
          • 關閉服務器不需要的功能。

          4 防范攻擊

          4.1跨站腳本攻擊(XSS)

          被動注入:用戶的輸入含有惡意腳本,而網站又能夠不加檢驗地接受這樣的輸入,進而保存到數據庫中。

          主動注入:用戶將含有惡意腳本的內容輸入到頁面文本框中,然后在屏幕上顯示出來。

          防御方法:

          1)使用Razor語法輸出的內容已經被編碼,可以不做任何其他處理

          例如:

          <h4>@Model.Field</h4>
          

          Html.ActionLink,Html.Action等方法會將路由參數編碼輸出

          2)大部分的XSS攻擊可通過對輸入內容進行編碼來阻止:Html.Encode,Html.AttributeEncode,Url.Encode

          3)對Js進行編碼

          使用Ajax.JavaScriptStringEncode

          4)將AntiXSS庫作為默認的編碼器(不建議使用,不靈活)

          ASP.NET 4.5 集成Anti-XSS Library,可以通過配置來對整個網站的輸出進行編碼。

          <system.web>
           <httpRuntime targetFramework="4.5" encoderType="System.Web.Security.AntiXss.AntiXssEncoder,System.Web"/>
           </system.web> 
          

          4.2跨站請求偽造(CSRF/XSRF)

          防御方法:

          1)使用Html隱藏域存儲用戶令牌,令牌可以存儲在Session里或者cookie里

          2)在視圖表單中使用@Html.AntiForgeryToken(),在控制器操作上添加屬性[ValidateAntiForgeryToken],注意表單一定要使用@Html.BeginForm生成

          實現機制:AntiForgeryToken方法向用戶瀏覽器cookie中寫入一個加密的數據,并在表單內插入一個隱藏欄位,每次刷新頁面時隱藏欄位的值都不同,每次執行控制器操作前,都會驗證隱藏欄位和瀏覽器cookie中的值是否相同,只有相同才允許執行控制器操作。

          使用限制:

          • 客戶端瀏覽器不能禁用cookie
          • 只對post請求有效
          • 若有XSS漏洞,則可輕易獲取令牌
          • 對Ajax請求不能傳遞令牌,即對Ajax無效

          3)使用冪等的Get請求,僅使用Post請求修改數據(僅僅是一定程度上限制這種攻擊而已)

          4)使用動作過濾器,驗證UrlReferrer

          擴展的動作過濾器:

          public class CSRFFilter:AuthorizeAttribute
           {
           public override void OnAuthorization(AuthorizationContext filterContext)
           {
           if (filterContext.HttpContext==null)
           {
           throw new HttpException("請求無效");
           }
           
           if (filterContext.HttpContext.Request.UrlReferrer==null)
           {
           throw new HttpException("請求無效");
           }
           
           if (filterContext.HttpContext.Request.UrlReferrer.Host !="sit.com")
           {
           throw new HttpException("來自非法網站");
           }
           }
          	}
          

          4.3 cookie盜竊

          cookie有兩種形式

          1)會話cookie:存儲在瀏覽器內存中,瀏覽器每次請求通過Http頭進行傳遞

          2)持久性cookie:存儲在硬盤上,同樣通過Http頭進行傳遞

          二者的區別:會話cookie常在會話結束時失效,而持久性cookie在下一次訪問站點時仍然有效。

          被竊取的原因:依賴于XSS漏洞,注入一段惡意腳本就能竊取。

          防御方法:

          1)在web.config對cookie進行設置

          <httpCookies httpOnlyCookies="true"/>,httpOnlyCookies指定為true表達僅服務器可以訪問,瀏覽器無法訪問

          2)在編寫代碼時為每個cookie單獨設置

          Response.Cookies["cok"].Value=Guid.NewGuid().ToString();

          Response.Cookies["cok"].HttpOnly=true;

          4.4重復提交

          防御方法:

          1)使用bind特性,設置想要綁定的屬性來,防止這種攻擊。也可以設置不要綁定的字屬性,但優先選擇設置要綁定的屬性。

          例:

          可以指定多個字段,用逗號分隔

          public ActionResult TestViewData([Bind(Include="Field,Field1,Field1")]ModelF mf)
          {
          	......
          }
          

          2)使用UpdateModel或TryUpdateModel

          3)使用ViewModel,明確規定View使用的數據模型

          4.5開放重定向

          防御方法:

          使用Url.IsLocalUrl檢測是否為本地url

          4.6 SQL注入攻擊

          防御方法:

          通過參數注入非法獲得或修改網站數據。

          使用參數化查詢來防止SQL注入攻擊。

          這篇文章中,Web開發人員和DZone MVB介紹了如何通過驗證數組來啟用和禁用一組元素的技術。

          今天,我們介紹如何通過驗證數組來啟用和禁用一組元素的技術。

          當涉及到前端的復雜業務邏輯時,Web應用程序變得越來越難以編寫。

          根據復雜性,可能需要您在提交之前接受一組輸入并驗證這些元素。

          我提交的最近一個屏幕需要多個DOM元素在啟用提交或“操作”按鈕之前處于特定狀態。

          當一組DOM元素處于特定狀態時,我們希望觸發其他元素。

          我知道你在想什么。為什么不使用jQuery進行驗證?

          原因如下:

          1. 對于這個任務,我們需要jQuery和不顯眼的驗證庫。這是我們真正不需要的兩個大型圖書館。

          2. 借助最新的JavaScript特性,您會驚訝于瀏覽器中已有多少功能,以及您甚至可能不再需要jQuery。

          3. 我想要一個快速和整潔的解決方案來解決這個問題。

          據說,我著手尋找一種更簡單的方式來有條件地驗證DOM元素組。

          一個簡單的例子

          讓我們用一個網格來設置一個簡單的場景。

          Views/Home/Index.cshtml

          @model EventViewModel

          @{

          ViewData["Title"]="Grouped Validations";

          }

          <style>

          th:nth-child(1) {

          width: 20px

          }

          </style>

          <h2>Events</h2>

          @using (Html.BeginForm())

          {

          <div class="btn-toolbar mb-3" role="toolbar" aria-label="Toolbar with button groups">

          <div class="btn-group mr-2" role="group" aria-label="First group">

          <button id="enabled-button" type="button" disabled="disabled" class="btn btn-info disabled">Enable</button>

          <button id="disabled-button" type="button" disabled="disabled" class="btn btn-info disabled">Disable</button>

          </div>

          </div>

          <table class="table table-condensed table-bordered table-striped">

          <thead>

          <tr>

          <th><input type="checkbox" id="select-all" /></th>

          <th>Event</th>

          <th>Begin Date</th>

          <th>End Date</th>

          </tr>

          </thead>

          <tbody>

          @foreach (var eventModel in Model.Events)

          {

          <tr>

          <td><input name="select" class="event-checkbox" type="checkbox" value="@eventModel.EventId" /></td>

          <td><a title="Go to @eventModel.Title" href="@eventModel.Url.AbsoluteUri">@eventModel.Title</a></td>

          <td>@eventModel.BeginDate.ToShortDateString()</td>

          <td>@eventModel.EndDate.ToShortDateString()</td>

          </tr>

          }

          </tbody>

          </table>

          }

          這個網格在左邊有復選框,帶有批按鈕來啟用和禁用事件。點擊標題中的復選框將選擇所有這些選項。

          首先,我們需要受用戶操作影響的元素。

          this.enabledButton=document.getElementById("enabled-button");

          this.disabledButton=document.getElementById("disabled-button");

          接下來,我們需要我們的驗證。這些驗證存儲在包含以下項目的數組中:

          1. 要啟用/禁用的元素。

          2. 一個簡單的條件。

          3. 條件為真時的lambda。

          4. 條件為false時的lambda。

          我們的驗證數組看起來像這樣:

          // Custom validations for enabling/disabling DOM elements based on conditions.

          this.validations=[

          {

          // When should the enable button be active?

          element: this.enabledButton,

          condition: ()=> {

          var checkedCheckboxes=areChecked();

          var valid=(

          // Do we have even one checkbox selected?

          checkedCheckboxes.length > 0

          );

          return valid;

          },

          trueAction: (elem)=> {

          elem.removeAttribute("disabled");

          elem.classList.remove("disabled");

          },

          falseAction: (elem)=> {

          elem.setAttribute("disabled", "disabled");

          elem.classList.add("disabled");

          }

          },

          // Second validation

          {

          // When should the disable button be active?

          element: this.disabledButton,

          condition: ()=> {

          var checkedCheckboxes=areChecked();

          var valid=(

          // No checkboxes are available, time to disable.

          checkedCheckboxes.length > 0

          );

          return valid;

          },

          trueAction: (elem)=> {

          elem.removeAttribute("disabled");

          elem.classList.remove("disabled");

          },

          falseAction: (elem)=> {

          elem.setAttribute("disabled", "disabled");

          elem.classList.add("disabled");

          }

          }

          ];

          我們基本上建立了一個“編碼陣列”。這個數組擁有我們編寫數據驅動代碼所需的一切。

          如果您發現 trueAction并且 falseAction,我們正在建立的拉姆達接收的元素。一旦我們收到元素,我們就會將某些屬性應用到DOM元素,當它是真或假操作時。

          我們的條件可以像我們需要的那樣復雜,以啟用或禁用某些DOM元素。

          啟用/禁用元素

          為了使我們的DOM元素可用或禁用,我們需要遍歷我們的驗證并對其執行操作; 所以,我們將使用該 map功能。

          function updateValidations() {

          Array.from(validations).map( (item, index, array)=> {

          if (item.condition()) {

          item.trueAction(item.element);

          } else {

          item.falseAction(item.element);

          }

          });

          }

          一旦我們有我們的功能來啟用或禁用DOM元素,我們需要將我們的事件附加到復選框。

          // Set the "select all" checkbox.

          var checkAll=document.getElementById("select-all");

          checkAll.addEventListener("change", checkAllCheckbox);

          我們的變化事件 checkAllCheckbox當然會稱為我們的 updateValidations();功能。

          function checkAllCheckbox() {

          var allCheckbox=document.getElementById("select-all");

          var eventCheckboxes=Array.from(

          document.getElementsByClassName("event-checkbox")

          );

          eventCheckboxes.map( (elem, index, array)=> {

          elem.checked=allCheckbox.checked;

          });

          updateValidations();

          }

          所有這些都不使用jQuery或驗證庫。

          瀏覽器阻斷

          當然,總會遇到一些......呃......某些瀏覽器。

          一些用戶報告了復選框單擊不與其他復選框一起工作的問題。

          我想知道=>舊版瀏覽器的arrow()語法。

          所以我去了caniuse.com以確認這是否可以與其他瀏覽器一起使用。

          你不知道嗎?我去了箭頭語法,發現這個:caniuse.com/#search=arrow

          由于我們不能使用箭頭語法,所以修復非常簡單。

          而不是這樣做:

          {

          // When should the enable button be active?

          element: this.enabledButton,

          condition: ()=> {

          var checkedCheckboxes=areChecked();

          var valid=(

          // Do we have even one checkbox selected?

          checkedCheckboxes.length > 0

          );

          return valid;

          },

          trueAction: (elem)=> {

          elem.removeAttribute("disabled");

          elem.classList.remove("disabled");

          },

          falseAction: (elem)=> {

          elem.setAttribute("disabled", "disabled");

          elem.classList.add("disabled");

          }

          },

          我們做得到:

          {

          // When should the enable button be active?

          element: this.enabledButton,

          condition: function () {

          var checkedCheckboxes=areChecked();

          var valid=(

          // Do we have even one checkbox selected?

          checkedCheckboxes.length > 0

          );

          return valid;

          },

          trueAction: function (elem) {

          elem.removeAttribute("disabled");

          elem.classList.remove("disabled");

          },

          falseAction: function (elem) {

          elem.setAttribute("disabled", "disabled");

          elem.classList.add("disabled");

          }

          },

          請記住,拉姆達只是匿名代表。用一個簡單的函數替換箭頭語法可以實現向后兼容性的奇跡。

          對于項目來源,請查看我的GitHub存儲庫。

          結論

          一旦建立起來,我就可以在多個頁面上使用這個功能,以便“引導”用戶在屏幕上可以或不可以執行的操作。當一個DOM元素被啟用時,它觸發另外兩個元素供用戶在屏幕上進行交互。

          這可以很容易地修改為使用提交按鈕。如果滿足所有這些條件,請啟用提交按鈕。如果不是,則禁用它直到滿足所有條件。

          再次,您可以根據需要將其設置為復雜或簡單。

          、點擊引用右鍵,管理NuGet程序包,輸入NPIO,選擇紅框選中的下載

          2、創建一個 ExcelController 控制器,將Index 方法生成視圖

          3、批量導入excel的頁面源碼:

          <h2>批量導入excel</h2>

          <div>

          @using (Html.BeginForm("Import", "Excel", FormMethod.Post, new { enctype="multipart/form-data" }))

          {

          <input name="files" type="file" multiple="multiple" id="=file" />

          <br />

          <br />

          <input name="submit" id="submit" type="submit" value="批量導入" />

          }

          </div>

          這里需要注意:file 的multiple屬性是能多個文件選中,enctype="multipart/form-data" 是上傳必須的表單屬性

          4、在ExcelController 控制器里面添加方法

          [HttpPost]

          public ActionResult Import(IEnumerable<HttpPostedFileBase> files)

          {

          // var fileName=file.FileName;

          var filePath=Server.MapPath(string.Format("~/{0}", "Files"));


          foreach (var file in files)

          {

          if (file !=null && file.ContentLength > 0)

          {

          var path=Path.Combine(filePath, file.FileName);

          file.SaveAs(path);

          DataTable excelTable=new DataTable();

          excelTable=ImportExcel.GetExcelDataTable(path);

          DataTable dbdata=new DataTable();

          dbdata.Columns.Add("ids");

          dbdata.Columns.Add("users");

          dbdata.Columns.Add("area");

          dbdata.Columns.Add("school");

          dbdata.Columns.Add("classes");

          dbdata.Columns.Add("name");

          dbdata.Columns.Add("phone");

          dbdata.Columns.Add("integration");

          dbdata.Columns.Add("states");

          dbdata.Columns.Add("createDate");

          dbdata.Columns.Add("refreshDate");

          for (int i=0; i < excelTable.Rows.Count; i++)

          {

          DataRow dr=excelTable.Rows[i];

          DataRow dr_=dbdata.NewRow();

          dr_["ids"]=dr["ID"];

          dr_["users"]=dr["用戶"];

          dr_["area"]=dr["區域"];

          dr_["school"]=dr["學校"];

          dr_["classes"]=dr["班級"];

          dr_["name"]=dr["姓名"];

          dr_["phone"]=dr["手機"];

          dr_["integration"]=dr["積分"];

          dr_["states"]=dr["狀態"];

          dr_["createDate"]=dr["創建時間"];

          dr_["refreshDate"]=dr["更新時間"];

          dbdata.Rows.Add(dr_);

          }

          RemoveEmpty(dbdata);

          string constr=System.Configuration.ConfigurationManager.AppSettings["cool"];

          SqlBulkCopyByDatatable(constr, "student", dbdata);

          }

          }


          return RedirectToAction("Index", "DataRefsh");

          }

          /// <summary>

          /// 大數據插入

          /// </summary>

          /// <param name="connectionString">目標庫連接</param>

          /// <param name="TableName">目標表</param>

          /// <param name="dtSelect">來源數據</param>

          public static void SqlBulkCopyByDatatable(string connectionString, string TableName, DataTable dtSelect)

          {

          using (SqlConnection conn=new SqlConnection(connectionString))

          {

          using (SqlBulkCopy sqlbulkcopy=new SqlBulkCopy(connectionString, SqlBulkCopyOptions.UseInternalTransaction))

          {

          try

          {

          sqlbulkcopy.DestinationTableName=TableName;

          sqlbulkcopy.BatchSize=20000;

          sqlbulkcopy.BulkCopyTimeout=0;//不限時間

          for (int i=0; i < dtSelect.Columns.Count; i++)

          {

          sqlbulkcopy.ColumnMappings.Add(dtSelect.Columns[i].ColumnName, dtSelect.Columns[i].ColumnName);

          }

          sqlbulkcopy.WriteToServer(dtSelect);

          }

          catch (System.Exception ex)

          {

          throw ex;

          }

          }

          }

          }

          protected void RemoveEmpty(DataTable dt)

          {

          List<DataRow> removelist=new List<DataRow>();

          for (int i=0; i < dt.Rows.Count; i++)

          {

          bool IsNull=true;

          for (int j=0; j < dt.Columns.Count; j++)

          {

          if (!string.IsNullOrEmpty(dt.Rows[i][j].ToString().Trim()))

          {

          IsNull=false;

          }

          }

          if (IsNull)

          {

          removelist.Add(dt.Rows[i]);

          }

          }

          for (int i=0; i < removelist.Count; i++)

          {

          dt.Rows.Remove(removelist[i]);

          }

          }

          這里需要注意:IEnumerable<HttpPostedFileBase> 是讀取多個文件的名稱,HttpPostedFileBase只能讀取一個,還有就是files 是file 控件name 相對應的

          5、string constr=System.Configuration.ConfigurationManager.AppSettings["cool"]; 需要在web.config 里面的appSettings 里面添加數據庫連接字符串的配置

          6、控制器import 方法里面有用到GetExcelDataTable 和GetCellValue 方法

          這里創建一個ImportExcel 類,創建以下兩個方法

          using System;

          using System.Collections.Generic;

          using System.Linq;

          using System.Web;

          using NPOI;

          using System.Data;

          using NPOI.SS.UserModel;

          using NPOI.HSSF.UserModel;

          using NPOI.XSSF.UserModel;

          using System.IO;

          namespace Cool{

          public class ImportExcel

          {

          public static DataTable GetExcelDataTable(string filePath)

          {

          IWorkbook Workbook;

          DataTable table=new DataTable();

          try

          {

          using (FileStream fileStream=new FileStream(filePath, FileMode.Open, FileAccess.Read))

          {

          //XSSFWorkbook 使用XLSX格式,HSSFWorkbook 使用XLS格式

          string fileExt=Path.GetExtension(filePath).ToLower();

          if (fileExt==".xls")

          {

          Workbook=new HSSFWorkbook(fileStream);

          }

          else if (fileExt==".xlsx")

          {

          Workbook=new XSSFWorkbook(fileStream);

          }

          else

          {

          Workbook=null;

          }

          }

          }

          catch (Exception ex)

          {

          throw ex;

          }

          //定位在第一個sheet

          ISheet sheet=Workbook.GetSheetAt(0);

          //第一行為標題行

          IRow headerRow=sheet.GetRow(0);

          int cellCount=headerRow.LastCellNum;

          int rowCount=sheet.LastRowNum;

          //循環添加標題列

          for (int i=headerRow.FirstCellNum; i < cellCount; i++)

          {

          DataColumn column=new DataColumn(headerRow.GetCell(i).StringCellValue);

          table.Columns.Add(column);

          }

          //數據

          for (int i=(sheet.FirstRowNum + 1); i <=rowCount; i++)

          {

          IRow row=sheet.GetRow(i);

          DataRow dataRow=table.NewRow();

          if (row !=null)

          {

          for (int j=row.FirstCellNum; j < cellCount; j++)

          {

          if (row.GetCell(j) !=null)

          {

          dataRow[j]=GetCellValue(row.GetCell(j));

          }

          }

          }

          table.Rows.Add(dataRow);

          }

          return table;

          }

          private static string GetCellValue(ICell cell)

          {

          if (cell==null)

          {

          return string.Empty;

          }

          switch (cell.CellType)

          {

          case CellType.Blank:

          return string.Empty;

          case CellType.Boolean:

          return cell.BooleanCellValue.ToString();

          case CellType.Error:

          return cell.ErrorCellValue.ToString();

          case CellType.Numeric:

          case CellType.Unknown:

          default:

          return cell.ToString();

          case CellType.String:

          return cell.StringCellValue;

          case CellType.Formula:

          try

          {

          HSSFFormulaEvaluator e=new HSSFFormulaEvaluator(cell.Sheet.Workbook);

          e.EvaluateInCell(cell);

          return cell.ToString();

          }

          catch

          {

          return cell.NumericCellValue.ToString();

          }

          }

          }

          }}

          這里需要注意:NPOI 只支持93-2007的offcie 的excel文件,如果是高版本的excel文件,需要降級,打開excel文件,另存為93-2007 的.xls 文件即可


          這樣就可以批量把文件數據導入到數據庫中了!!!


          主站蜘蛛池模板: 久久精品一区二区三区资源网| 国产自产在线视频一区| 波多野结衣中文一区| 一区二区三区免费视频观看 | 无码人妻一区二区三区免费| 亚洲一区二区三区AV无码| 精品一区二区三区免费毛片 | 久久亚洲色一区二区三区| 在线观看视频一区二区| 国产精品香蕉在线一区| 亚洲爆乳精品无码一区二区三区| 日韩在线一区视频| 久久精品成人一区二区三区| 国产91久久精品一区二区| 日本一区二区免费看| 亚洲啪啪综合AV一区| 国产精品小黄鸭一区二区三区| 美女视频黄a视频全免费网站一区| 亚洲日韩一区二区一无码| 精品国产一区二区三区无码| 无码国产精品一区二区免费3p | 国产av夜夜欢一区二区三区| 亚洲av无码片vr一区二区三区| 精品欧洲av无码一区二区| 国产高清在线精品一区| 国产精品揄拍一区二区| 久久一区二区三区精华液使用方法| 国产福利一区二区三区在线视频 | 国产一区玩具在线观看| 中文字幕一区二区三区乱码| 国产一区二区三区精品视频 | 无码午夜人妻一区二区不卡视频 | 国产精品熟女视频一区二区| 波多野结衣中文一区| 亚洲一区二区三区免费| 精品国产一区二区三区免费 | 国产在线观看精品一区二区三区91| 爱爱帝国亚洲一区二区三区| 国产一区二区三区在线观看影院| 无码人妻一区二区三区在线水卜樱| 久久综合一区二区无码|