带有WCF的ReactiveUI命令在更新可观察属性时导致线程错误
我试图使用ReactiveUI命令进行WCF调用,并使用ObservablesPropertyHelper捕获结果字符串。使用下面的代码,我收到以下错误消息- “调用线程无法访问此对象,因为其他线程拥有它” WCF调用在访问ObservableForProperty-消息和/或提升其属性更改时返回错误 如果有人需要其他详细信息/代码,请告诉我 ViewModel:UserService.Authenticate是对WCF端点的代理调用带有WCF的ReactiveUI命令在更新可观察属性时导致线程错误,wcf,reactiveui,Wcf,Reactiveui,我试图使用ReactiveUI命令进行WCF调用,并使用ObservablesPropertyHelper捕获结果字符串。使用下面的代码,我收到以下错误消息- “调用线程无法访问此对象,因为其他线程拥有它” WCF调用在访问ObservableForProperty-消息和/或提升其属性更改时返回错误 如果有人需要其他详细信息/代码,请告诉我 ViewModel:UserService.Authenticate是对WCF端点的代理调用 public class LoginViewModel :
public class LoginViewModel : ReactiveObject, IRoutableViewModel
{
public LoginViewModel(IScreen hostScreen , MainViewModel appRootViewModel, IUserService userService)
{
HostScreen = hostScreen;
UserService = userService;
Application = appRootViewModel;
var canLogin = this.WhenAny(x => x.LoginName, x => x.Password, (l, p) =>
!String.IsNullOrWhiteSpace(l.Value) && !String.IsNullOrWhiteSpace(p.Value));
LoginCommand = new ReactiveCommand(canLogin);
var loggedIn = LoginCommand.RegisterAsync(_ => Observable.Start(() =>
{
var request = new Request
{
UserIdentity = new User.Identity
{
Login = LoginName,
Password = new User.Password { Old = Password }
}
};
var authenticationResult = UserService.Authenticate(request).Authenticated;
return authenticationResult ? "Login Succeeded...Continuing"
: "Login Failed...Please try again";
}));
loggedIn.Subscribe(s =>
{
if (s == "Login Succeeded...Continuing to Analytics")
{
HostScreen.Router.Navigate.Execute(Application);
}
});
message = new ObservableAsPropertyHelper<string>(loggedIn,
s =>
{
raisePropertyChanged("Message");
});
public类LoginViewModel:ReactiveObject,IRoutableViewModel
{
公共登录视图模型(IScreen hostScreen、主视图模型ApprotViewModel、IUserService用户服务)
{
主机屏幕=主机屏幕;
UserService=UserService;
应用程序=ApprotViewModel;
var canLogin=this.WhenAny(x=>x.LoginName,x=>x.Password,(l,p)=>
!String.IsNullOrWhiteSpace(l.Value)和&!String.IsNullOrWhiteSpace(p.Value));
LoginCommand=newreactivecommand(canLogin);
var loggedIn=LoginCommand.RegisterAsync(=>Observable.Start(()=>
{
var请求=新请求
{
UserIdentity=新用户.Identity
{
Login=LoginName,
密码=新用户。密码{Old=Password}
}
};
var authenticationResult=UserService.Authenticate(请求).Authenticated;
返回authenticationResult?“登录成功…继续”
:“登录失败…请重试”;
}));
loggedIn.Subscribe(s=>
{
如果(s==“登录成功…继续分析”)
{
HostScreen.Router.Navigate.Execute(应用程序);
}
});
消息=新的ObservablesPropertyHelper(loggedIn,
s=>
{
raisePropertyChanged(“消息”);
});
查看隐藏代码:
public partial class LoginView : IViewFor<LoginViewModel>
{
public LoginView()
{
InitializeComponent();
this.WhenAnyValue(x => x.ViewModel).BindTo(this, x => x.DataContext);
this.Bind(ViewModel, model => model.Password, x => x.password.Text);
this.Bind(ViewModel, model => model.LoginName, view => view.userName.Text);
this.OneWayBind(ViewModel, model => model.Message, x => x.message.Content);
this.OneWayBind(ViewModel, x => x.LoginCommand, x => x.login.Command);
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(LoginViewModel), typeof(LoginView), new PropertyMetadata(null));
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (LoginViewModel)value; }
}
public LoginViewModel ViewModel
{
get
{
return (LoginViewModel)GetValue(ViewModelProperty);
}
set
{
SetValue(ViewModelProperty,
value);
}
}
}
public分部类LoginView:IViewFor
{
公共登录视图()
{
初始化组件();
this.whenyValue(x=>x.ViewModel).BindTo(this,x=>x.DataContext);
this.Bind(ViewModel,model=>model.Password,x=>x.Password.Text);
this.Bind(ViewModel,model=>model.LoginName,view=>view.userName.Text);
这个.OneWayBind(ViewModel,model=>model.Message,x=>x.Message.Content);
这个.OneWayBind(ViewModel,x=>x.LoginCommand,x=>x.login.Command);
}
公共静态只读从属属性ViewModelProperty=
DependencyProperty.Register(“ViewModel”、typeof(LoginView模型)、typeof(LoginView)、new PropertyMetadata(null));
对象IViewFor.ViewModel
{
获取{return ViewModel;}
设置{ViewModel=(LoginViewModel)值;}
}
公共登录视图模型视图模型
{
得到
{
返回(LoginViewModel)GetValue(ViewModelProperty);
}
设置
{
SetValue(ViewModelProperty,
价值);
}
}
}
}您的大多数代码都是正确的(除了设置
消息的地方,只需使用loggedIn.ToProperty
),但我记得,WCF试图通过摆弄SynchronizationContext来“帮助您”,您需要禁用它(但我不确定如何做到这一点)更新:通过告诉观察者回调在当前同步上下文上运行来修复
.ObserveOn(SynchronizationContext.Current)
下面是解决上述问题的LoginCommand可观察代码。最后一行是编辑
var loggedIn = LoginCommand.RegisterAsync(_ => Observable.Start(() =>
{
Session<NullT> init = new Session<NullT>
{
SqlKey = System.Configuration.ConfigurationManager.AppSettings["sharedKey"].ToString()
};
var initResponse = UserService.Initialize(init);
var authenticationResult = false;
if (initResponse.SessionOk)
{
initResponse.UserIdentity = new User.Identity
{
Login = LoginName,
Password = new User.Password { Old = Password }
};
authenticationResult = UserService.Authenticate(initResponse).Authenticated;
return authenticationResult ? "Login Succeeded"
: "Login Failed...Please try again";
}
else return "Failed to Initialize.";
}).ObserveOn(SynchronizationContext.Current));
var loggedIn=LoginCommand.RegisterAsync(=>Observable.Start(()=>
{
会话初始化=新会话
{
SqlKey=System.Configuration.ConfigurationManager.AppSettings[“sharedKey”].ToString()
};
var initResponse=UserService.Initialize(init);
var authenticationResult=false;
if(initResponse.SessionOk)
{
initResponse.UserIdentity=新用户.Identity
{
Login=LoginName,
密码=新用户。密码{Old=Password}
};
authenticationResult=UserService.Authenticate(initResponse).Authenticated;
返回authenticationResult?“登录成功”
:“登录失败…请重试”;
}
否则返回“初始化失败。”;
}).ObserveOn(SynchronizationContext.Current));
我添加了[ServiceBehavior(UseSynchronizationContext=false)][CallbackBehavior(UseSynchronizationContext=false)]这对我的服务类没有帮助,因为它给了我相同的结果。需要注意的是,当我用一个方法存根替换身份验证调用时,这是有效的-因此Paul您是正确的,因为它与WCFalso有关。那么您关于TopProperty的建议是否适用于常规属性,或者是否需要使用支持字段ObservablesPropertyHelper消息是否有效?在第一次传递时,即使设置初始值param,如-->loggedIn.ToProperty(this,x=>x.message,string.Empty),消息上仍会出现null异常;另一个观察结果是,如果成功验证并路由到MainView,则返回-I get{“调用线程必须是STA,因为许多UI组件都需要它。”}不知何故,由于WCF,我被抛出了当前上下文-我是停留在LoginView还是导航到另一个视图?