Silverlight与Asp.Net MVC 通讯
最近一周分配了个任务,编辑配置,需要做成web的。要求有拖拽、旋转、选择多边形范围⊙﹏⊙。
考虑到自己的烂jq,申请用SilverLight,居然可以用这个没娘的孩儿。
Silverlight需要与MVC主项目通讯,无外乎是Get、Post,别的没用到。
- 获取地址
WebRequest创建时需要Uri,而且是绝对路径的,需要获取xap所在的地址。
var scriptObject = HtmlPage.Window.GetProperty("location") as ScriptObject; var hostUrl = scriptObject.GetProperty("href").ToString();
这样获取的就是xap所在的页面的地址,再加入控制器方法名即可创建WebRequest。
- Get
参数传递需要拼接在请求里的Url里。
var pstr = string.Join("&", parameters.Select(p => string.Format("{0}={1}", p.Name, p.Value))); uriStr += string.Format("/?{0}", pstr);
创建好WebRequest后可设置属性Method为"GET"即可。
然后就可以通过 request.BeginGetResponse的方法获取回应。
如果需要从返回值里读出数据,则只需
DataContractJsonSerializer ser = new DataContractJsonSerializer(returnType); object obj = ser.ReadObject(responseStream);
obj即为解析完的数据。
- Post
Post是创建WebRequest与Get相同,只不过参数不能放在Url里,而是提交表单的形式。传递多个参数需要使用boundary标记。
request.ContentType = "multipart/form-data; boundary=---------------------------" + boundary;
boundary为随机字符串,在一次Post中保持一致。
具体boundary使用参考了Netsuite的博客。
参数需要序列化MVC才能解析,除非MVC使用别的解析方法。序列化时可写入临时的MemoryStream,设置Request的ContentLength为MemoryStream的长度后,再Copy给RequestStream
public static void Post<TResult>( string controllerMethod, Action<TResult> responseCallback, params Parameter<object>[] parameters) { string boundary = GetBoundaryStr(); HttpWebRequest request = GetRequest(controllerMethod, RequestMethod.Post); request.ContentType = "multipart/form-data; boundary=---------------------------" + boundary; MemoryStream ms = new MemoryStream(); foreach (var item in parameters) { var parameter = item.Value; byte[] data = null; if (parameter is string) { data = SerializeStrParameter(boundary, item.Name, (string)parameter); } else if (parameter is byte[]) { data = SerializeBinParameter(boundary, item.Name, (byte[])parameter); } else if (parameter is object) { data = SerializeObjectParameter(boundary, parameter, item.Name); } if (data != null) { ms.Write(data, 0, data.Length); } } var endData = Encoding.UTF8.GetBytes("-----------------------------" + boundary + "--"); ms.Write(endData, 0, endData.Length); ms.Seek(0, SeekOrigin.Begin); request.ContentLength = ms.Length; AsyncCallback requestCallback = new AsyncCallback((iar) => { using (Stream stream = request.EndGetRequestStream(iar)) { ms.CopyTo(stream); } request.BeginGetResponse( new AsyncCallback(ResponseCallback), Tuple.Create<HttpWebRequest, Type, Delegate>(request, typeof(TResult), responseCallback)); }); request.BeginGetRequestStream(requestCallback, request); }
具体序列化字符串的方法为
private static byte[] SerializeStrParameter(string boundary, string parameterName, string parameter) { StringBuilder sb = new StringBuilder(); sb.AppendLine("-----------------------------" + boundary); sb.AppendLine(string.Format("Content-Disposition: form-data; name=\"{0}\"", parameterName)); sb.AppendLine(); sb.AppendLine(parameter); return Encoding.UTF8.GetBytes(sb.ToString()); }
序列化byte数组(可用于提交文件)方法为
private static byte[] SerializeBinParameter(string boundary, string parameterName, byte[] parameter) { if (parameter == null) { return new byte[0]; } StringBuilder sb = new StringBuilder(); sb.AppendLine("-----------------------------" + boundary); sb.AppendLine(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"fakeFile.bin\"", parameterName)); sb.AppendLine("Content-Type: application/octet-stream"); sb.AppendLine(); byte[] strBin = Encoding.UTF8.GetBytes(sb.ToString()); byte[] rt = Encoding.UTF8.GetBytes("\r\n"); byte[] re = new byte[strBin.Length + parameter.Length + rt.Length]; Array.Copy(strBin, re, strBin.Length); Array.Copy(parameter, 0, re, strBin.Length, parameter.Length); Array.Copy(rt, 0, re, strBin.Length + parameter.Length, rt.Length); return re; }
序列化对象方法为
private static byte[] SerializeObjectParameter(string boundary, object parameter, string initialName = "") { if (parameter == null) { return new byte[0]; } MemoryStream ms = new MemoryStream(); var propertys = parameter.GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty); initialName = string.IsNullOrEmpty(initialName) ? "" : initialName + "."; foreach (var property in propertys) { if (property.PropertyType.IsArray) { Array array = (Array)property.GetValue(parameter, null); for (int i = 0; i < array.Length; i++) { var data = SerializeObjectParameter( boundary, array.GetValue(i), string.Format("{0}{1}[{2}]", initialName, property.Name, i)); ms.Write(data, 0, data.Length); } } else if (property.PropertyType.IsValueType || property.PropertyType == typeof(string)) { var data = SerializeStrParameter( boundary, initialName + property.Name, property.GetValue(parameter, null).ToString()); ms.Write(data, 0, data.Length); } else { throw new Exception(); } } return ms.ToArray(); }