網站/IIS/Web/WCF服務 訪問共享目錄 映射 的解決方案


目錄

問題案例

原因分析

解決問題

總結

問題案例

環境

電腦A:winform程序;

電腦B:部署了一個文件上傳的WCF服務在IIS上。且該服務的配置文件中已經增加

<identity impersonate="true" password="1234" userName="Test" />
//該賬戶同時存在於電腦B和電腦C中

電腦C:公布的共享路徑;

在A的winform程序連接B的WCF服務上傳文件,B的WCF服務將文件保存至C的共享路徑中。

結果:路徑無法訪問。

System.UnauthorizedAccessException: 對路徑“”的訪問被拒絕

對比:同樣的操作使用wevservice和.aspx都可以正常訪問共享路徑並操作。

期望/最終目的:找到可以在WCF中訪問共享路徑的解決方案。

 

原因分析

排除:權限不足的原因

因為其他兩種方式(WebService和.aspx)在沒有配置【Asp.net模擬】的身份驗證方式之前,也是同樣的錯誤。使用【Asp.net模擬】的身份驗證后,就可以正常操作。

所以我在想是不是因為WCF未能調用【Asp.net模擬】的身份驗證?或者說該項配置對WCF無效?

 

================2014-10-20==============

排除:服務引用方式

嘗試使用 Web References 的方式添加WCF服務的引用(之前是Service References )。問題依舊。

 

解決問題

 

方案:在WCF服務的靜態構造函數中,通過調用net use 命令實現路徑映射,從而實現訪問。

示例代碼如下:  

  1     public class FileService : IFileService
  2     {
  3         /// <summary>
  4         /// FileService的靜態構造函數
  5         /// </summary>
  6         static FileService()
  7         {
  8             string shareName="\\192.168.1.2\shares";
  9             //用戶名勿比指定共享服務器的IP或名稱,否則會引起1312錯誤
 10             string user="192.168.1.2\Test";
 11             string pwd="123";
 12             NetUseHelper.Build(shareName, user, pwd, string.Empty);//不指定盤符,避免引起盤符被占用的錯誤
 13             /*        
 14                          *不建議指定盤符。因為IIS的網站默認是在IUser賬戶下運行的,而映射只針對'建立時的賬戶'有效。所以IUser下的映射又是無法預知的。
 15                           所以應該建立連接后,仍然使用共享地址訪問文件或目錄。
 16              */
 17         }
 18 
 19     }
 20 
 21     /// <summary>
 22     /// net use 建立映射的功能模塊
 23     /// </summary>
 24     public static class NetUseHelper
 25     {
 26         /// <summary>
 27         /// 所有支持的驅動器號
 28         /// </summary>
 29         static readonly string[] driveNames = { "ZYXWVUTSRQPONMLKJIHGFEDC" };
 30         /// <summary>
 31         /// 建立映射
 32         /// </summary>
 33         /// <param name="sharename">共享路徑</param>
 34         /// <param name="user">用戶名。為 null 不指定用戶
 35         /// <para>請務必使用共享服務器的IP或PC名稱+用戶名,例如:192.168.1.1\User。否則可能引起1312錯誤</para>
 36         /// </param>
 37         /// <param name="password">密碼。為 null 不指定密碼</param>
 38         /// <param name="devicename">磁盤驅動器名稱,例如(C:)。為 null 自動分配驅動器號 。為 空 不指定驅動器號</param>
 39         /// <returns>驅動器名稱</returns> 
 40         public static string Build(string sharename, string user = null, string password = null, string devicename = null)
 41         {
 42             if (devicename != string.Empty)//為空時在已有的列表中得不到信息,所以不用判斷了
 43             {
 44                 //得到當前所有的映射驅動器及地址
 45                 var netUseList = GetAllDevic();
 46 
 47                 //標准格式
 48                 sharename = @"\\" + sharename.Trim('\\');
 49 
 50                 if (devicename == null)//自動分配驅動器號
 51                 {
 52                     for (int i = 0; i < driveNames.Length; i++)
 53                     {
 54                         string name = driveNames[i];
 55                         if (netUseList.ContainsKey(name)) continue;//已存在
 56                         devicename = name;
 57                         break;
 58 
 59                     }
 60                     if (devicename == null)
 61                         throw new ArgumentException("當前沒有可用的驅動器號.");
 62                 }
 63                 else
 64                 {
 65                     //標准格式
 66                     devicename = devicename.Trim('\\', ':');
 67 
 68                     //判斷是否已存在相同的共享
 69                     foreach (var kv in netUseList)
 70                     {
 71                         if (kv.Value == null) continue;
 72                         //驅動器號和共享路徑一致
 73                         if (string.Equals(kv.Key, devicename, StringComparison.CurrentCultureIgnoreCase)
 74                             && string.Equals(kv.Value, sharename, StringComparison.CurrentCultureIgnoreCase))
 75                             return devicename;//已存在,返回
 76                     }
 77                     //共享沒在用,但其他占用驅動器號
 78                     if (netUseList.ContainsKey(devicename))
 79                         throw new ArgumentException("驅動器號" + devicename + "正在使用.");
 80                 }
 81 
 82             }
 83             using (System.Diagnostics.Process myProcess = new System.Diagnostics.Process())
 84             {
 85                 string command = string.Format(@"use ");
 86                 if (devicename != string.Empty)
 87                 {
 88                     command += devicename.Trim('\\', ':') + ": ";
 89 
 90                 }
 91                 command += string.Format("\"{0}\" ", sharename);
 92                 if (user != null)
 93                 {
 94                     command += string.Format(@"""{0}"" /user:""{1}"" ", password, user);
 95                 }
 96                 System.IO.File.AppendAllText("d:\\log.txt", command);
 97                 //通過net use的命令 創建共享。
 98                 System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo("net ", command);
 99                 info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
100                 info.CreateNoWindow = true;
101                 info.UseShellExecute = false;
102                 info.RedirectStandardError = true;
103                 myProcess.StartInfo = info;
104                 myProcess.Start();
105                 myProcess.WaitForExit(6000);
106                 string errormsg = myProcess.StandardError.ReadToEnd();
107 
108                 myProcess.Close();
109 
110                 if (!string.IsNullOrEmpty(errormsg))
111                     throw new InvalidOperationException(errormsg);
112             }
113             return devicename;
114         }
115 
116         /// <summary>
117         /// 獲取當前所有的驅動器
118         /// <para>Key:盤符</para>
119         /// <para>Value:盤符ProviderName(源路徑信息)。如果為本地磁盤則為null</para>
120         /// </summary>
121         /// <returns></returns>
122         private static Dictionary<string, string> GetAllDevic()
123         {
124             //得到當前所有的驅動器
125             var devicList = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
126             var selectQuery = new System.Management.SelectQuery("select * from win32_logicaldisk");
127             var searcher = new System.Management.ManagementObjectSearcher(selectQuery);
128 
129             foreach (System.Management.ManagementObject disk in searcher.Get())
130             {
131                 var devName = disk["DeviceID"];
132                 if (devName == null)
133                     devName = disk["Name"];
134                 var diskName = devName.ToString().Trim('\\', ':');
135                 devicList.Add(diskName, null);
136                 var access = disk["Access"];
137                 if (access == null || access.ToString() != "0") continue;//不可訪問
138                 var drivetype = disk["DriveType"];
139                 if (drivetype == null || drivetype.ToString() != "4") continue;//不是網絡驅動器
140                 var providername = disk["ProviderName"];
141                 if (providername == null) continue;//沒有映射源
142 
143                 devicList[diskName] = providername.ToString();
144             }
145             return devicList;
146         }
147     }

 

測試:多個客戶端同時操作未報錯。

另外,建議在對文件操作時進行異常捕捉判斷,如果捕捉到FileNotFoundException 和 DirectoryNotFoundException ,說明可能發生了映射不可用的情況,應當自動建立映射。

 

總結

從一開始接觸到這個BUG,到解決,斷斷續續經歷了一周左右。寫代碼的時間也就半天不到,更多的是在查找資料、各地“求救”,很無望的趕腳。。。好了,碎碎念結束。

其實仔細想想,冷靜下來,才會有更多的思路。

最后,如果各位有更好的方式?還望示下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM