网站/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;
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 = providername.ToString();
144 }
145 return devicList;
146 }
147 }
测试:多个客户端同时操作未报错。
另外,建议在对文件操作时进行异常捕捉判断,如果捕捉到FileNotFoundException 和 DirectoryNotFoundException ,说明可能发生了映射不可用的情况,应当自动建立映射。
总结
从一开始接触到这个BUG,到解决,断断续续经历了一周左右。写代码的时间也就半天不到,更多的是在查找资料、各地“求救”,很无望的赶脚。。。好了,碎碎念结束。
其实仔细想想,冷静下来,才会有更多的思路。
最后,如果各位有更好的方式?还望示下。
页:
[1]