Data Service - 8. ASP.NET AJAX Sys.Data
[ 2009-04-29 12:01:45 | 作者: yuhen ]
ASP.NET AJAX 4.0 新增了对 ADO.NET Data Service 的支持,我们可以用 JavaScript 直接完成对 .svc 的调用。
以下示例使用的是 ASP.NET AJAX 4.0 Preview 4。在使用前,别忘了添加 MicrosoftAjax JS 引用。
该库的核心类是 Sys.Data.AdoNetServiceProxy,我们的服务操作也是通过它来完成的。
1. Query
通过资源寻址路径(URI),我们可以查询所需的实体对象。默认情况下,Sys.Data 会自动使用 JSON 格式。
我们还可以用 Sys.Data.AdoNetQueryBuilder 来创建包含查询选项的 Request URI,避免手工书写可能造成的错误。
2. Insert
AdoNetServiceProxy.insert 用于新增实体对象,并且会自动处理服务器返回的新增实体信息(比如 Id)。
3. Update
AdoNetServiceProxy.update 更新的实体对象必须包含 Meatadata 信息,否则无法定位更新目标。
4. Remove
要删除实体,同样要求实体对象包含 Metadata 进行资源定位。
5. Batch
Sys.Data 同样提供了批量提交的能力。
我们监听一下 ASP.NET Development Server,看看提交内容。
6. Lazy Load
利用 AdoNetServiceProxy.fetchDeferredProperty() 我们可以载入延迟加载的导航属性。
当然,也可以载入 Many-to-Many。
附:
AdoNetServiceProxy.fetchData() 可用于执行非 GET 操作(比如 Service Operation),不过 MicrosoftAdoNet.js 中代码似乎没写全,导致该方法无法正常使用。
-------- 分割线 ------------
我对 Microsoft ASP.NET AJAX 比较陌生,用起来有点别扭。不过作为 .NET 一个重要的客户端库,看样子还是得花点时间研究一下。
评论Feed: http://www.rainsts.net/feed.asp?q=comment&id=813
以下示例使用的是 ASP.NET AJAX 4.0 Preview 4。在使用前,别忘了添加 MicrosoftAjax JS 引用。
<script src="MicrosoftAjax.js" type="text/javascript"></script> <script src="MicrosoftAjaxAdoNet.js" type="text/javascript"></script>
该库的核心类是 Sys.Data.AdoNetServiceProxy,我们的服务操作也是通过它来完成的。
1. Query
通过资源寻址路径(URI),我们可以查询所需的实体对象。默认情况下,Sys.Data 会自动使用 JSON 格式。
<script type="text/javascript">
function dataServiceQuery()
{
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
var users = dataService.query("/Users?$top=1", callbackSuccess, callbackFailed);
}
function callbackSuccess(result, context, operation)
{
alert(result[0].Name);
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>我们还可以用 Sys.Data.AdoNetQueryBuilder 来创建包含查询选项的 Request URI,避免手工书写可能造成的错误。
<script type="text/javascript">
function dataServiceQuery()
{
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
var queryBuilder = new Sys.Data.AdoNetQueryBuilder("/Users");
queryBuilder.set_skip(2);
queryBuilder.set_top(1);
var users = dataService.query(queryBuilder.toString(), callbackSuccess, callbackFailed);
}
...
</script>2. Insert
AdoNetServiceProxy.insert 用于新增实体对象,并且会自动处理服务器返回的新增实体信息(比如 Id)。
<script type="text/javascript">
function dataServiceInsert()
{
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
var user = { Name:"userx", Age:18 };
dataService.insert(user, "/Users", callbackSuccess, callbackFailed);
}
function callbackSuccess(result, context, operation)
{
alert("Success!\n User Id = " + result.Id);
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>3. Update
AdoNetServiceProxy.update 更新的实体对象必须包含 Meatadata 信息,否则无法定位更新目标。
<script type="text/javascript">
var user;
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
function dataServiceQuery()
{
dataService.query("/Users?$top=1", function(result, context, operation)
{
user = result[0];
alert(user.Name);
});
}
function dataServiceUpdate()
{
user.Age += 1;
dataService.update(user, callbackSuccess, callbackFailed);
}
function callbackSuccess(result, context, operation)
{
alert("Success!");
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>
<input id="btnQuery" type="button" value="Query" onclick="javascript:dataServiceQuery()" />
<input id="btnUpdate" type="button" value="Update" onclick="javascript:dataServiceUpdate()" />4. Remove
要删除实体,同样要求实体对象包含 Metadata 进行资源定位。
<script type="text/javascript">
var user;
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
function dataServiceQuery()
{
dataService.query("/Users?$top=1", function(result, context, operation)
{
user = result[0];
alert(user.Name);
});
}
function dataServiceRemove()
{
dataService.remove(user, callbackSuccess, callbackFailed);
}
function callbackSuccess(result, context, operation)
{
alert("Success!");
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>
<input id="btnTest" type="button" value="Query" onclick="javascript:dataServiceQuery()" />
<input id="btnDelete" type="button" value="Delete" onclick="javascript:dataServiceRemove()" />5. Batch
Sys.Data 同样提供了批量提交的能力。
<script type="text/javascript">
function dataServiceBatch()
{
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
var actionSequence = dataService.createActionSequence();
actionSequence.addInsertAction({ Name: "userA", Age: 1 }, "/Users");
actionSequence.addInsertAction({ Name: "userB", Age: 2 }, "/Users");
actionSequence.addInsertAction({ Name: "userC", Age: 3 }, "/Users");
actionSequence.execute(callbackSuccess, callbackFailed);
}
function callbackSuccess(result, context, operation)
{
alert("Success!");
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>我们监听一下 ASP.NET Development Server,看看提交内容。
Receive: Return Code: 0x00000000 POST /Test.svc/$batch HTTP/1.1 Accept: */* Accept-Language: zh-cn Referer: http://localhost:2394/Default.aspx Content-Type: multipart/mixed; boundary=batch_8a71-67bb-9993 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; ... CIBA) Host: localhost:2394 Content-Length: 986 Connection: Keep-Alive Cache-Control: no-cache --batch_8a71-67bb-9993 Content-Type: multipart/mixed;boundary=changeset_0b42-6552-980f --changeset_0b42-6552-980f Content-Type: application/http Content-Transfer-Encoding: binary POST /Users HTTP/1.1 Content-ID: 0 Host: localhost:2394 Accept: application/json Accept-Charset: utf-8 Content-Type: application/json;charset=utf-8 {"Name":"userA","Age":1} --changeset_0b42-6552-980f Content-Type: application/http Content-Transfer-Encoding: binary POST /Users HTTP/1.1 Content-ID: 1 Host: localhost:2394 Accept: application/json Accept-Charset: utf-8 Content-Type: application/json;charset=utf-8 {"Name":"userB","Age":2} --changeset_0b42-6552-980f Content-Type: application/http Content-Transfer-Encoding: binary POST /Users HTTP/1.1 Content-ID: 2 Host: localhost:2394 Accept: application/json Accept-Charset: utf-8 Content-Type: application/json;charset=utf-8 {"Name":"userC","Age":3} --changeset_0b42-6552-980f-- --batch_8a71-67bb-9993-- Send: Return Code: 0x00000000 HTTP/1.1 202 Accepted Server: ASP.NET Development Server/9.0.0.0 Date: Wed, 29 Apr 2009 03:53:32 GMT X-AspNet-Version: 2.0.50727 Cache-Control: no-cache Content-Type: multipart/mixed; boundary=batchresponse_28aa2225-b569-4de0-b34f-9052a3cbbe41 Content-Length: 2251 Connection: Close Send: Return Code: 0x00000000 --batchresponse_28aa2225-b569-4de0-b34f-9052a3cbbe41 Content-Type: multipart/mixed; boundary=changesetresponse_e9b5f241-4472-421f-9650-aa34285295a6 --changesetresponse_e9b5f241-4472-421f-9650-aa34285295a6 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 201 Created Content-ID: 0 Content-Type: application/json;charset=utf-8 Cache-Control: no-cache Location: http://localhost:2394/Test.svc/Users(57) DataServiceVersion: 1.0; { "d": { "__metadata": { "uri": "http://localhost:2394/Test.svc/Users(57)", "type": "TestModel.User" }, "Id": 57, "Name": "userA", "Age": 1, "UserDetail": { "__deferred": { "uri": "http://localhost:2394/Test.svc/Users(57)/UserDetail" } }, "Orders": { "__deferred": { "uri": "http://localhost:2394/Test.svc/Users(57)/Orders" } } } } --changesetresponse_e9b5f241-4472-421f-9650-aa34285295a6 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 201 Created Content-ID: 1 Content-Type: application/json;charset=utf-8 Cache-Control: no-cache Location: http://localhost:2394/Test.svc/Users(58) DataServiceVersion: 1.0; { "d": { "__metadata": { "uri": "http://localhost:2394/Test.svc/Users(58)", "type": "TestModel.User" }, "Id": 58, "Name": "userB", "Age": 2, "UserDetail": { "__deferred": { "uri": "http://localhost:2394/Test.svc/Users(58)/UserDetail" } }, "Orders": { "__deferred": { "uri": "http://localhost:2394/Test.svc/Users(58)/Orders" } } } } --changesetresponse_e9b5f241-4472-421f-9650-aa34285295a6 Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 201 Created Content-ID: 2 Content-Type: application/json;charset=utf-8 Cache-Control: no-cache Location: http://localhost:2394/Test.svc/Users(59) DataServiceVersion: 1.0; { "d": { "__metadata": { "uri": "http://localhost:2394/Test.svc/Users(59)", "type": "TestModel.User" }, "Id": 59, "Name": "userC", "Age": 3, "UserDetail": { "__deferred": { "uri": "http://localhost:2394/Test.svc/Users(59)/UserDetail" } }, "Orders": { "__deferred": { "uri": "http://localhost:2394/Test.svc/Users(59)/Orders" } } } } --changesetresponse_e9b5f241-4472-421f-9650-aa34285295a6-- --batchresponse_28aa2225-b569-4de0-b34f-9052a3cbbe41--
6. Lazy Load
利用 AdoNetServiceProxy.fetchDeferredProperty() 我们可以载入延迟加载的导航属性。
<script type="text/javascript">
function dataServiceQuery()
{
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
dataService.query("/Users?$top=1", function(result, context, operation)
{
var user = result[0];
dataService.fetchDeferredProperty(user, "UserDetail", callbackSuccess, callbackFailed);
});
}
function callbackSuccess(result, context, operation)
{
alert("Success!\nUser: " + result.Name + "\nDetail Telephone: " + result.UserDetail.Telephone);
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>当然,也可以载入 Many-to-Many。
<script type="text/javascript">
function dataServiceQuery()
{
var dataService = new Sys.Data.AdoNetServiceProxy("Test.svc");
dataService.query("/Users?$top=1", function(result, context, operation)
{
var user = result[0];
dataService.fetchDeferredProperty(user, "Orders", callbackSuccess, callbackFailed);
});
}
function callbackSuccess(result, context, operation)
{
var sb = new Sys.StringBuilder();
sb.appendLine("Success!");
sb.appendLine("User: " + result.Name);
sb.appendLine("Orders: ");
for (var i = 0; i < result.Orders.length; i++)
{
var order = result.Orders[i];
sb.appendLine(" " + order.Title + ", " + order.Price);
}
alert(sb.toString());
}
function callbackFailed(error, context, operation)
{
alert(error._message);
}
</script>附:
AdoNetServiceProxy.fetchData() 可用于执行非 GET 操作(比如 Service Operation),不过 MicrosoftAdoNet.js 中代码似乎没写全,导致该方法无法正常使用。
function Sys$Data$AdoNetServiceProxy$fetchData(operation, parameters, mergeOption, httpVerb,
succeededCallback, failedCallback, timeout, userContext)
{
/// <summary locid="M:J#Sys.Data.AdoNetServiceProxy.fetchData" />
/// <param name="operation"></param>
/// <param name="parameters" type="Object" mayBeNull="true" optional="true"></param>
/// <param name="mergeOption" type="Sys.Data.MergeOption" mayBeNull="true" optional="true"></param>
/// <param name="httpVerb" type="String" mayBeNull="true" optional="true"></param>
/// <param name="succeededCallback" type="Function" mayBeNull="true" optional="true"></param>
/// <param name="failedCallback" type="Function" mayBeNull="true" optional="true"></param>
/// <param name="timeout" type="Number" integer="true" mayBeNull="true" optional="true"></param>
/// <param name="userContext" mayBeNull="true" optional="true"></param>
/// <returns type="Sys.Net.WebRequest"></returns>
var e = Function._validateParams(arguments,
[
{ name: "operation" },
{ name: "parameters", type: Object, mayBeNull: true, optional: true },
{ name: "mergeOption", type: Sys.Data.MergeOption, mayBeNull: true, optional: true },
{ name: "httpVerb", type: String, mayBeNull: true, optional: true },
{ name: "succeededCallback", type: Function, mayBeNull: true, optional: true },
{ name: "failedCallback", type: Function, mayBeNull: true, optional: true },
{ name: "timeout", type: Number, mayBeNull: true, integer: true, optional: true },
{ name: "userContext", mayBeNull: true, optional: true }
]);
if (e) throw e;
if (!this.get_serviceUri())
{
throw Error.invalidOperation(Sys.Data.AdoNetRes.requiredUri);
}
if (!operation)
{
throw Error.argumentNull("operation");
}
var request, oldTimeout = null;
if (typeof (timeout) !== "undefined")
{
oldTimeout = this.get_timeout();
this.set_timeout(timeout);
}
if (parameters)
{
var q = "";
for (var name in parameters)
{
if (q)
{
q += "&";
}
q += encodeURIComponent(name) + "=" + encodeURIComponent(parameters[name]);
}
if (operation.indexOf("?") === -1)
{
operation += "?" + q;
}
else
{
operation += "&" + q;
}
}
request = this.query(operation, succeededCallback, failedCallback, userContext);
if (oldTimeout !== null)
{
this.set_timeout(oldTimeout);
}
return request;
}-------- 分割线 ------------
我对 Microsoft ASP.NET AJAX 比较陌生,用起来有点别扭。不过作为 .NET 一个重要的客户端库,看样子还是得花点时间研究一下。
[最后修改由 yuhen, 于 2009-04-29 14:49:31]
评论Feed: http://www.rainsts.net/feed.asp?q=comment&id=813
这篇日志没有评论。










