ASP.NET访问网络驱动器(映射磁盘)

也许很多朋友在做WEB项目的时候都会碰到这样一个需求:

当用户上传文件时,需要将上传的文件保存到另外一台专门的文件服务器。

 

要实现这样一个功能,有两种解决方案:

方案一、在文件服务器上新建一站点,用来接收上传的文件,然后保存。

方案二、将文件服务器的指定目录共享给WEB服务器,用来保存文件。

 

方案一不用多说,应该是很简单的了,将上传文件的FORM表单的ACTION属性指向文件服务器上的站点即可,我们来重点说下方案二。

 

也许你会说,其实方案二也很简单,在WEB服务器上做下磁盘映射,然后直接访问不就行了。其实不是这样的,IIS默认账户为NETWORK_SERVICE,该账户是没权限访问共享目录的,所以当你把站点部署到IIS上的时候,再访问映射磁盘就会报“找不到路径”的错误。所以,直接创建磁盘映射是行不通的,我们需要在程序中用指定账户创建映射,并用该账户运行IIS进程,下面来说下详细步骤及相关代码。

 

1、在文件服务器上创建共享目录,并新建访问账户。

比如共享目录为:\\192.168.0.9\share

 

访问账户为:user-1 密码为:123456

 

2、在WEB服务器上新建用户:user-1 密码为:123456,用户组选择默认的user组即可。

 

3、在WEB项目中新建公共类WNetHelper

[csharp] view plain copy
 
  1. using System.Runtime.InteropServices;  
  2.    
  3. public class WNetHelper  
  4. {  
  5.     [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]  
  6.     private static extern uint WNetAddConnection2(NetResource lpNetResource, string lpPassword, string lpUsername, uint dwFlags);  
  7.    
  8.     [DllImport("Mpr.dll", EntryPoint = "WNetCancelConnection2")]  
  9.     private static extern uint WNetCancelConnection2(string lpName, uint dwFlags, bool fForce);  
  10.    
  11.     [StructLayout(LayoutKind.Sequential)]  
  12.     public class NetResource  
  13.     {  
  14.         public int dwScope;  
  15.    
  16.         public int dwType;  
  17.    
  18.         public int dwDisplayType;  
  19.    
  20.         public int dwUsage;  
  21.    
  22.         public string lpLocalName;  
  23.    
  24.         public string lpRemoteName;  
  25.    
  26.         public string lpComment;  
  27.    
  28.         public string lpProvider;  
  29.     }  
  30.    
  31.     /// <summary>  
  32.     /// 为网络共享做本地映射  
  33.    /// </summary>  
  34.     /// <param name="username">访问用户名(windows系统需要加计算机名,如:comp-1\user-1)</param>  
  35.     /// <param name="password">访问用户密码</param>  
  36.     /// <param name="remoteName">网络共享路径(如:\\192.168.0.9\share)</param>  
  37.     /// <param name="localName">本地映射盘符</param>  
  38.     /// <returns></returns>  
  39.     public static uint WNetAddConnection(string username, string password, string remoteName, string localName)  
  40.     {  
  41.         NetResource netResource = new NetResource();  
  42.    
  43.         netResource.dwScope = 2;  
  44.         netResource.dwType = 1;  
  45.         netResource.dwDisplayType = 3;  
  46.         netResource.dwUsage = 1;  
  47.         netResource.lpLocalName = localName;  
  48.         netResource.lpRemoteName = remoteName.TrimEnd('\\');  
  49.         uint result = WNetAddConnection2(netResource, password, username, 0);  
  50.    
  51.         return result;  
  52.     }  
  53.    
  54.     public static uint WNetCancelConnection(string name, uint flags, bool force)  
  55.     {  
  56.         uint nret = WNetCancelConnection2(name, flags, force);  
  57.    
  58.         return nret;  
  59.     }  
  60. }  

 

4、为IIS指定运行账户user-1

要实现此功能,有两种办法:

a) 在web.config文件中的<system.web>节点下,添加如下配置:<identity impersonate="true" userName="user-1" password="123456" />

b) 在WEB项目中添加公用类LogonImpersonate

[csharp] view plain copy
 
  1. public class LogonImpersonate : IDisposable  
  2. {  
  3.     static public string DefaultDomain  
  4.     {  
  5.         get  
  6.         {  
  7.             return ".";  
  8.         }  
  9.     }  
  10.    
  11.     const int LOGON32_LOGON_INTERACTIVE = 2;  
  12.     const int LOGON32_PROVIDER_DEFAULT = 0;  
  13.    
  14.     [System.Runtime.InteropServices.DllImport("Kernel32.dll")]  
  15.     extern static int FormatMessage(int flag, ref   IntPtr source, int msgid, int langid, ref   string buf, int size, ref   IntPtr args);  
  16.    
  17.     [System.Runtime.InteropServices.DllImport("Kernel32.dll")]  
  18.     extern static bool CloseHandle(IntPtr handle);  
  19.    
  20.     [System.Runtime.InteropServices.DllImport("Advapi32.dll", SetLastError = true)]  
  21.     extern static bool LogonUser(  
  22.     string lpszUsername,  
  23.     string lpszDomain,  
  24.     string lpszPassword,  
  25.     int dwLogonType,  
  26.     int dwLogonProvider,  
  27.     ref   IntPtr phToken  
  28.     );  
  29.    
  30.     IntPtr token;  
  31.     System.Security.Principal.WindowsImpersonationContext context;  
  32.    
  33.     public LogonImpersonate(string username, string password)  
  34.     {  
  35.         if (username.IndexOf("\\") == -1)  
  36.         {  
  37.             Init(username, password, DefaultDomain);  
  38.         }  
  39.         else  
  40.         {  
  41.             string[] pair = username.Split(new char[] { '\\' }, 2);  
  42.             Init(pair[1], password, pair[0]);  
  43.         }  
  44.     }  
  45.     public LogonImpersonate(string username, string password, string domain)  
  46.     {  
  47.         Init(username, password, domain);  
  48.     }  
  49.     void Init(string username, string password, string domain)  
  50.     {  
  51.         if (LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref   token))  
  52.         {  
  53.             bool error = true;  
  54.             try  
  55.             {  
  56.                 context = System.Security.Principal.WindowsIdentity.Impersonate(token);  
  57.                 error = false;  
  58.             }  
  59.             finally  
  60.             {  
  61.                 if (error)  
  62.                     CloseHandle(token);  
  63.             }  
  64.         }  
  65.         else  
  66.         {  
  67.             int err = System.Runtime.InteropServices.Marshal.GetLastWin32Error();  
  68.    
  69.             IntPtr tempptr = IntPtr.Zero;  
  70.             string msg = null;  
  71.    
  72.             FormatMessage(0x1300, ref   tempptr, err, 0, ref   msg, 255, ref   tempptr);  
  73.    
  74.             throw (new Exception(msg));  
  75.         }  
  76.     }  
  77.     ~LogonImpersonate()  
  78.     {  
  79.         Dispose();  
  80.     }  
  81.     public void Dispose()  
  82.     {  
  83.         if (context != null)  
  84.         {  
  85.             try  
  86.             {  
  87.                 context.Undo();  
  88.             }  
  89.             finally  
  90.             {  
  91.                 CloseHandle(token);  
  92.                 context = null;  
  93.             }  
  94.         }  
  95.     }  
  96. }  

 

在访问映射磁盘之前首先调用此类为IIS更换运行用户:LogonImpersonate imper = new LogonImpersonate("user-1", "123456");

 

5、在访问共享目录前,调用WNetHelper.WNetAddConnection,添加磁盘映射

[csharp] view plain copy
 
  1. public static bool CreateDirectory(string path)  
  2. {  
  3.     uint state = 0;  
  4.     if (!Directory.Exists("Z:"))  
  5.     {  
  6.         state = WNetHelper.WNetAddConnection(@"comp-1\user-1", "123456", @"\\192.168.0.9\share", "Z:");  
  7.     }  
  8.     if (state.Equals(0))  
  9.     {  
  10.         Directory.CreateDirectory(path);  
  11.         return true;  
  12.     }  
  13.     else  
  14.     {  
  15.         throw new Exception("添加网络驱动器错误,错误号:" + state.ToString());  
  16.     }  
  17. }  

 

6、完成。

 

简洁代码就是:

LogonImpersonate imper = new LogonImpersonate("user-1", "123456");

WNetHelper.WNetAddConnection(@"comp-1\user-1", "123456", @"\\192.168.0.9\share", "Z:");
Directory.CreateDirectory(@"Z:\newfolder");

file1.SaveAs(@"Z:\newfolder\test.jpg");

posted @ 2016-09-07 09:37  kylin2016  阅读(481)  评论(0编辑  收藏  举报