- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发连接到 WCF 4.0 双工服务以实现某种平面文件处理的 ASP.NET 4.0 Webforms 客户端应用程序。当用户在 Page_Load 事件上进入页面时,我为客户端订阅了双工服务,这是因为在某些情况下我需要通知所有客户端:
A) 启动进程的客户端必须在进程启动时得到通知。
B) 处理文件时必须通知启动进程的客户端。
C) 启动进程的客户必须在整个进程完成时得到通知。
D) 如果新客户(订阅者)在流程已经启动时进入,则必须收到特定通知。
E) 如果有多个客户端(订阅者)在其中一个启动进程时处于事件状态,则其他客户端必须收到特定通知。
我已经编写了这个逻辑,但是我在尝试完成特定订阅者通知时遇到了很多问题,WCF 似乎将 Web 应用程序的所有客户端/实例都识别为相同,我收到了所有启动进程的客户端中的通知,如果我打开其他浏览器并启动新 session (在 ASP.NET 上),我会收到相同的通知,没有什么特别的。
在这里你可以看到我的代码的简化版本
WCF 服务接口(interface)
using System.ServiceModel;
namespace WcfService
{
[ServiceContract(CallbackContract = typeof(IService1DuplexCallback))]
public interface IService1
{
[OperationContract(IsOneWay = true)]
void Subscribe(string idSesion);
[OperationContract(IsOneWay = true)]
void ProcessFiles(string idSesion);
}
public interface IService1DuplexCallback
{
[OperationContract(IsOneWay = true)]
void NotifyProcessWorking();
[OperationContract(IsOneWay = true)]
void NotifyProcessStarted();
[OperationContract(IsOneWay = true)]
void NotifyFileProcessed(int id);
[OperationContract(IsOneWay = true)]
void NotifyProcessFinished();
}
}
WCF 服务实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using System.Threading.Tasks;
namespace WcfService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
private static List<KeyValuePair<string, IService1DuplexCallback>> _clients = new List<KeyValuePair<string, IService1DuplexCallback>>();
private static bool _isProcessStarted;
private static string _sessionStarted = string.Empty;
public void Subscribe(string idSesion)
{
lock (_clients)
{
if (!_clients.Any(x => string.Equals(x.Key, idSesion, StringComparison.InvariantCultureIgnoreCase)))
{
var callback = OperationContext.Current.GetCallbackChannel<IService1DuplexCallback>();
if (callback != null)
{
var currentSubscriber = new KeyValuePair<string, IService1DuplexCallback>(idSesion, callback);
_clients.Add(currentSubscriber);
}
}
}
if (_isProcessStarted)
{
NotifyProcessWorking(idSesion);
}
}
public void ProcessFiles(string idSesion)
{
_isProcessStarted = true;
_sessionStarted = idSesion;
try
{
var mockFileCount = 23;
var r = new Random();
NotifyStarted();
NotifyProcessWorking();
Parallel.For(0, mockFileCount, (i) =>
{
//Do a lot of specific validations... (time betweeen 5 secs and 2 minutes per file)
var time = r.Next(5000, 120000);
Thread.Sleep(time);
NotifyFileProcessed(i);
});
NotifyProcessFinished();
}
catch (Exception ex)
{
throw;
}
_isProcessStarted = false;
}
private static void NotifyStarted()
{
var c = _clients.FirstOrDefault(x => string.Equals(x.Key, _sessionStarted, StringComparison.InvariantCultureIgnoreCase));
try
{
c.Value.NotifyProcessStarted();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
private static void NotifyFileProcessed(int idFile)
{
var c = _clients.FirstOrDefault(x => string.Equals(x.Key, _sessionStarted, StringComparison.InvariantCultureIgnoreCase));
try
{
c.Value.NotifyFileProcessed(idFile);
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
private static void NotifyProcessFinished()
{
foreach (var c in _clients)
{
try
{
c.Value.NotifyProcessFinished();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
private static void NotifyProcessWorking(string idSesion = "")
{
if (string.IsNullOrEmpty(idSesion))
{
foreach (var c in _clients)
{
try
{
c.Value.NotifyProcessWorking();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
else
{
var c = _clients.FirstOrDefault(x => string.Equals(x.Key, idSesion, StringComparison.InvariantCultureIgnoreCase));
try
{
c.Value.NotifyProcessWorking();
}
catch (Exception)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
}
}
WCF 服务 Web.config
<?xml version="1.0"?>
<configuration>
<appSettings/>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime/>
</system.web>
<system.serviceModel>
<services>
<service name="WcfService.Service1">
<endpoint address="" binding="wsDualHttpBinding" bindingConfiguration="FileProcessorDuplexBinding"
name="FileProcessorDuplexEndPoint" contract="WcfService.IService1"/>
</service>
</services>
<bindings>
<wsDualHttpBinding>
<binding name="FileProcessorDuplexBinding" closeTimeout="00:30:00" openTimeout="00:30:00"
sendTimeout="00:30:00" receiveTimeout="00:30:00" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<reliableSession inactivityTimeout="00:30:00"/>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="None"/>
</binding>
</wsDualHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
ASP.NET WebForm 客户端用户界面
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script src="Scripts/jquery-2.1.4.min.js"></script>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnStart" runat="server" Text="Start Process" OnClientClick="Start();"/>
<br/>
<br/>
<asp:Label ID="lblStatus" runat="server" Text="[Process Status]"></asp:Label>
</div>
<script>
function Start() {
var loc = window.location.href;
var dataValue = "{}";
$.ajax({
type: "POST",
url: loc + "/StartProcess",
contentType: 'application/json',
data: dataValue,
dataType: 'json',
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
},
success: function(result) {
}
});
}
setInterval(function () {
var loc = window.location.href;
var dataValue = "{ id: '1' }";
$.ajax({
type: "POST",
url: loc + "/CheckMessage",
contentType: 'application/json',
data: dataValue,
dataType: 'json',
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
},
success: function(result) {
processMessage(result.d);
}
});
}, 1000);
function processMessage(msg) {
if (msg) {
switch (msg) {
case "working":
alert("Process currently working");
$('[id$=lblStatus]').attr('disabled', true);
break;
case "started":
$('#<%=lblStatus.ClientID%>').html("Process started");
break;
case "finished":
$('#<%=lblStatus.ClientID%>').html("Process finished");
break;
default:
var data = msg.split(":");
$('#<%=lblStatus.ClientID%>').html("File Processed: " + data[1]);
break;
}
}
}
</script>
</form>
</body>
</html>
ASP.NET WebForm 客户端代码隐藏
using System;
using System.Collections.Concurrent;
using System.ServiceModel;
using System.Web.Services;
using System.Web.UI;
using WebApplication.ServiceReference1;
namespace WebApplication
{
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
public partial class Default : Page, IService1Callback
{
private static ConcurrentQueue<string> _serviceReceivedMessages = new ConcurrentQueue<string>();
private static string _sessionId = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
_sessionId = Session.SessionID;
var proxyDuplex = new Service1Client(new InstanceContext(new Default()));
proxyDuplex.Subscribe(_sessionId);
}
}
[WebMethod]
public static void StartProcess()
{
var proxyDuplex = new Service1Client(new InstanceContext(new Default()));
proxyDuplex.ProcessFiles(_sessionId);
}
[WebMethod]
public static string CheckMessage(string id)
{
var message = string.Empty;
_serviceReceivedMessages.TryDequeue(out message);
return message ?? (message = string.Empty);
}
public void NotifyProcessWorking()
{
_serviceReceivedMessages.Enqueue("working");
}
public void NotifyProcessStarted()
{
_serviceReceivedMessages.Enqueue("started");
}
public void NotifyFileProcessed(int id)
{
_serviceReceivedMessages.Enqueue("processed:"+id);
}
public void NotifyProcessFinished()
{
_serviceReceivedMessages.Enqueue("finished");
}
}
}
ASP.NET WebForm 客户端 Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime/>
</system.web>
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="FileProcessorDuplexBinding"
closeTimeout="00:30:00" openTimeout="00:30:00" receiveTimeout="00:30:00"
sendTimeout="00:30:00" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
clientBaseAddress="http://localhost:62778/TempUri">
<reliableSession inactivityTimeout="00:30:00" />
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:62778/Service1.svc" binding="wsDualHttpBinding"
bindingConfiguration="FileProcessorDuplexBinding" contract="ServiceReference1.IService1"
name="FileProcessorDuplexEndPoint" />
</client>
</system.serviceModel>
</configuration>
在这里你可以download包含完整代码的 Visual Studio 2015 解决方案。
我想知道我的代码有什么问题,我认为这种行为是可能的,但不明白为什么 WCF 没有通知特定的客户端。
谢谢
更新 1
我做了@JuanK 建议我(当时)的所有更改,但没有成功,行为继续相同,我添加了一个新的控制台项目来测试相同的服务,并且在该项目中工作正常
但在 ASP.NET 项目中错误继续存在,第二个客户端收到所有通知
在这里你可以download VS 解决方案已更新(此时)
最佳答案
WCF 不会通知特定的客户端,因为您已编码该服务必须向每个人发送通知。
private static void NotifyProcessFinished()
{
//FOR EACH CLIENT
foreach (var c in _clients)
{
try
{
c.Value.NotifyProcessFinished();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
另一方面,有一些ServiceBehavior
和我已在此处修复的静态字段问题:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
private static List<KeyValuePair<string, IService1DuplexCallback>> _clients = new List<KeyValuePair<string, IService1DuplexCallback>>();
private static bool _isProcessStarted;
private string _sessionStarted = string.Empty;
public void Subscribe(string idSesion)
{
lock (_clients)
{
if (!_clients.Any(x => string.Equals(x.Key, idSesion, StringComparison.InvariantCultureIgnoreCase)))
{
var callback = OperationContext.Current.GetCallbackChannel<IService1DuplexCallback>();
if (callback != null)
{
var currentSubscriber = new KeyValuePair<string, IService1DuplexCallback>(idSesion, callback);
_clients.Add(currentSubscriber);
}
}
}
if (_isProcessStarted)
{
NotifyProcessWorking(idSesion);
}
}
public void ProcessFiles(string idSesion)
{
_isProcessStarted = true;
_sessionStarted = idSesion;
try
{
var mockFileCount = 2;
var r = new Random();
NotifyStarted();
NotifyProcessWorking();
Parallel.For(0, mockFileCount, (i) =>
{
//Do a lot of specific validations... (time betweeen 5 secs and 2 minutes per file)
var time = 5000;//r.Next(5000, 120000);
Thread.Sleep(time);
NotifyFileProcessed(i);
});
NotifyProcessFinished();
}
catch (Exception ex)
{
throw;
}
_isProcessStarted = false;
}
private void NotifyStarted()
{
var c = _clients.FirstOrDefault(x => string.Equals(x.Key, _sessionStarted, StringComparison.InvariantCultureIgnoreCase));
try
{
c.Value.NotifyProcessStarted();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
private void NotifyFileProcessed(int idFile)
{
var c = _clients.FirstOrDefault(
x => string.Equals(x.Key, _sessionStarted,
StringComparison.InvariantCultureIgnoreCase)
);
try
{
c.Value.NotifyFileProcessed(idFile);
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
private void NotifyProcessFinished()
{
//STILL SAME YOU HAVE IT. JUST IN CASE
foreach (var c in _clients)
{
try
{
c.Value.NotifyProcessFinished();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
private static void NotifyProcessWorking(string idSesion = "")
{
if (string.IsNullOrEmpty(idSesion))
{
foreach (var c in _clients)
{
try
{
c.Value.NotifyProcessWorking();
}
catch (Exception ex)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
else
{
var c = _clients.FirstOrDefault(x => string.Equals(x.Key, idSesion, StringComparison.InvariantCultureIgnoreCase));
try
{
c.Value.NotifyProcessWorking();
}
catch (Exception)
{
lock (_clients)
{
_clients.Remove(c);
}
}
}
}
}
如果你有一个单一的实例行为和一个静态字段:静态字段在所有连接之间共享,所以例如 _sessionStarted
始终获取上次连接的状态。
所以我将服务行为更改为 PerSession
允许每个特定 session /连接保留非静态字段,而像 List<KeyValuePair<string, IService1DuplexCallback>> _clients
这样的静态字段仍然在他们之间共享。这也意味着一些方法现在是非静态方法。
关于c# - WCF 双工 : Send callback to a specific subscribed ASP. NET Webforms 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32077970/
所以我试图将 MiniProfiler ( https://github.com/MiniProfiler/dotnet ) 用于 WebForms 网站。我所做的是: 使用 nuget 安装软件包
是否有等同于 Webforms 的 MvcBuildViews? 最佳答案 不。 另一种方法是将构建后操作添加到 Visual Studio 项目并让它运行 aspnet_compiler.exe “
是否有使用 CSP(内容安全策略)将 WebForms 项目中动态创建的脚本列入白名单的安全方法? 使用 unsafe-inline像下面它的工作原理,但不推荐。 context.Response.H
我们正在尝试使用在经典模式应用程序池中运行的 ASP.NET WebForms 应用程序配置 MiniProfiler(无法将其更改为集成)。我们无法让处理程序工作,因此加载资源失败。 为了解决这个问
是否 ASP.Net 核心 1.0 支持.Net WebForm 项目吗?或者它只是一个 MVC 环境?我也可以在那里创建经典的 Web 服务(asmx)吗? 最佳答案 简短回答:不,ASP.NET
我正在尝试将数据从 webform 传递到方法背后的代码并在 webform 中取回值,然后打印它。我最初测试了以下代码以简单地将请求发布到方法,获取字符串并在页面中打印,它可以工作,但是在尝试将数据
我创建了一个新的 ASP.NET 4.5 WebForms 项目,并发现了一堆与 GridView、DetailsView 和其他数据相关组件以及 MSAjax 相关的额外 javascript 文件
我正在使用带有模型绑定(bind)和 Entity Framework 5 的 .net 4.5 WebForms。 我的网络表单的一部分:
在搜索了很多类似的帖子、解决方法之后,我决定自己发帖。 Compilation Error Description: An error occurred during the compilation
我将在一个项目中工作,我们将在该项目中将 ASP 经典页面重写为 ASP.NET WebForm。我从未使用过 VB、VBScript、ASP Classic。好处是有大量关于 VB6、VB.NET、
在 vs2012 中,f7 键在 aspx/ascx/masterpage 文件的 Markup 和 Codebehind 之间切换。在我重新安装系统之前,Vs2013 的行为方式相同。现在它只会从
我正在尝试登录网站并自动保存 HTML 页面(我希望能够定期执行此操作)。从表面上看,这是一个典型的现代网站,如果用户直接导航到“锁定”的 URL,则会弹出一个登录表单,登录后,用户将被重定向到预期页
我看到人们在以Webform进行路由时使用星号符号。我只是不明白像下面这样的星号的重要性 routes.MapPageRoute( "View Category", /
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 8 年前。 Improve this qu
我正在尝试在 aspx 页面中执行类似的操作: 我收到错误“预处理器指令必须显示为行上的第一个非空白字符”。我怎样才能做到这一点?
我想渲染一个表单。字段行的 HTML 应该是这样的: 当字段类型为文本时,li.class 必须相同。 我覆盖了 field_row block : {% block
目前我所有的网络表单文件 (.aspx) 都在我的项目 (VS 2012) 的根文件夹中。 我创建了一个名为“pages”的新文件夹,并使用母版页向其中添加了一个新的网络表单 (WebForm1)。当
我正在为销售文员制作一个 asp.net、c#、webforms 网站。我在屏幕顶部有四个主要按钮,我将使用它们来实现很多功能。我想要做的是将这些按钮设置为键盘上的 F1、F2、F3 和 F4 键。
我在网络表单上有两个按钮,它们的显示高度不同。这发生在我更新 Gravity Forms 之后。 参见 http://topdek.nl/prijs/ ,输入随机名称、电子邮件地址和电话号码,单击“V
在我的 WebForms 应用程序中,我有一个 CustomValidator 控件。该控件执行我创建的 JavaScript 函数。如果此函数返回 false,则表单将不会提交。此验证器与标准 Re
我是一名优秀的程序员,十分优秀!