为将来可能会发现此问题的任何人提供解决方案的后续行动。
我尝试以多种方式发送请求:
- 当您将 WCF 服务作为 ServiceReference 添加到 ScriptManager 时创建的 AJAX 脚本对象。因此,如果 WCF 服务类是带有 GetProgress 方法的 ProgressService,我在 JavaScript 中创建了一个新的 ProgressService 对象并调用 progressService.GetProgress()。
- 一个 XmlHttpRequest 请求。
- 一个 jQuery $.getJson() 请求。
- 一个 Sys.Net.WebRequest 请求。
- Sys.Net.WebServiceProxy 请求。
事实证明,即使发送了客户端请求,即没有被 ASP.NET ScriptManager 缓冲,如果 WCF 服务是 IIS 中同一网站的一部分,它也不会响应。
因此,我没有创建一个完全独立的 WCF 项目和一个完全独立的 IIS 网站,而是切换到了传统的 ASP.NET (SOAP) Web 服务 (.asmx)。
我能够在 Visual Studio 中保留同一项目的 .asmx 服务部分,并在 IIS 中保留网站。请求在回发期间发送,服务在回发期间做出响应。
在 ScriptManager 下将其添加为 ServiceReference 之后,我还能够使用基本相同的脚本对象,创建一个新的 ProgressWebService(),然后调用 progressWebService.GetProgress()。传递给 GetProgress() 的回调处理程序然后处理响应并更新 UI。
网络服务:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Caching;
namespace MyNamespace
{
public class Progress
{
public string Message { get; set; }
public bool Complete { get; set; }
}
[WebService(Namespace = "MyNamespace")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class ProgressWebService : System.Web.Services.WebService
{
protected static Dictionary<string, Progress> ProgressMessages = new Dictionary<string, Progress>();
[WebMethod]
public Progress GetProgress(string progressId)
{
return ProgressMessages.ContainsKey(progressId) ? ProgressMessages[progressId] : new Progress();
}
[WebMethod]
public void SetProgress(string progressId, string progress, bool complete)
{
if (ProgressMessages.ContainsKey(progressId))
{
ProgressMessages[progressId].Message = progress;
ProgressMessages[progressId].Complete = complete;
}
else
ProgressMessages.Add(progressId, new Progress() { Message = progress, Complete = complete });
}
[WebMethod]
public void SetProgressComplete(string progressId, bool complete)
{
if (ProgressMessages.ContainsKey(progressId))
ProgressMessages[progressId].Complete = complete;
else
ProgressMessages.Add(progressId, new Progress() { Complete = complete });
}
[WebMethod]
public void AddProgress(string progressId, string progress)
{
if (ProgressMessages.ContainsKey(progressId))
ProgressMessages[progressId].Message += progress;
else
ProgressMessages.Add(progressId, new Progress() { Message = progress });
}
}
}
客户端:
<%@ Page language="c#" CodeFile="About.aspx.cs" Inherits="MyNamespace.About" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script type="text/javascript">
var ProgressServiceInterval; // global interval var, so it can be set and cleared across functions
function btnBackup_Click(sender, e) {
sender.disabled = true; // disable the backup button, so the request isn't duplicated
// start getting the backup progress from the web service
var progressService = new MyNamespace.ProgressWebService();
progressService.SetProgressComplete('<%= strBackupProgressGuid %>', false, null, null, null);
ProgressServiceInterval = setInterval('setBackupProgress()', 1000); // get progress once per second
}
function setBackupProgress() {
var progressService = new MyNamespace.ProgressWebService();
progressService.GetProgress('<%= strBackupProgressGuid %>', progressCallback, null, null);
}
function progressCallback(result) {
var txtBackupOutput = $get('<%= txtBackupOutput.ClientID %>');
try {
// show the progress message
txtBackupOutput.value = result.Message;
// stop checking if progress is complete
if (result.Complete == true) clearInterval(ProgressServiceInterval);
// scroll the textarea to the bottom
txtBackupOutput.scrollTop = txtBackupOutput.scrollHeight - txtBackupOutput.clientHeight;
} catch (ex) {
}
}
</script>
</head>
<body>
<form id="frmMyForm" method="post" runat="server">
<ajaxToolkit:ToolkitScriptManager runat="Server" EnablePartialRendering="true" EnablePageMethods="true" ID="ScriptManager1" >
<Services>
<asp:ServiceReference Path="ProgressWebService.asmx" />
</Services>
</ajaxToolkit:ToolkitScriptManager>
<asp:UpdatePanel ID="updBackup" runat="server" RenderMode="Inline">
<ContentTemplate>
<asp:UpdateProgress ID="updBackupProgress" AssociatedUpdatePanelID="updBackup" runat="server" DynamicLayout="false">
<ProgressTemplate>
<div style="text-align:center;margin-bottom:-32px;">
<img src="loading.gif" alt="Loading..." />
</div>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:Button ID="btnBackup" runat="server" CssClass="SubmitButton" Text="Back Up Data" UseSubmitBehavior="false" OnClientClick="btnBackup_Click(this, event);" />
<br /><br />
<asp:TextBox ID="txtBackupOutput" runat="server" ReadOnly="true" TextMode="MultiLine" Rows="10" Width="100%" Wrap="true" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
和服务器端:
namespace MyNamespace
{
public partial class About
{
protected string strBackupProgressGuid
{
get
{
if (Session["strBackupProgressGuid"] == null)
Session["strBackupProgressGuid"] = Guid.NewGuid().ToString();
return Session["strBackupProgressGuid"] as string;
}
}
ProgressWebService _progressService;
protected ProgressWebService progressService
{
get
{
return _progressService = _progressService ?? new ProgressWebService();
}
}
void btnBackup_Click(object sender, EventArgs e)
{
progressService.SetProgress(strBackupProgressGuid, "Started\r\n", false);
System.Threading.Thread.Sleep(10000);
progressService.AddProgress(strBackupProgressGuid, "+10\r\n");
System.Threading.Thread.Sleep(10000);
progressService.AddProgress(strBackupProgressGuid, "+20\r\n");
System.Threading.Thread.Sleep(10000);
progressService.AddProgress(strBackupProgressGuid, "+30\r\n");
progressService.SetProgressComplete(strBackupProgressGuid, true);
}
}
}