数据源为lightswitch 提供的ODATA服务,本质就是ASP.NET 的WCF data service .
IIS 下站点使用的是FORMS验证方式。
现在使用WPF客户端来消费这个ODATA,通过在客户端添加引用,目前可以获取或操作ODATA数据。但在使用时发现二个问题,不知如何解决(估计是一个问题引起的)。先上代码。
OmsProxy.ApplicationData dataSvc = null;
dataSvc =new OmsProxy.ApplicationData( new Uri("http://localhost/oms/ApplicationData.svc/")); //此处使用其他正式生产服务器,也是一样问题
dataSvc.Format.UseJson();
dataSvc.Credentials = new NetworkCredential("user", "pwd"); form认证用户名及密码
二个调用数据的处理(button 一次点击)
var query = from a in dataSvc.OrderBills select a;
MessageBox.Show(query.ToList().Count.ToString());
var query1 = from b in dataSvc.PayInfos select b;
MessageBox.Show(query1.ToList().Count.ToString());
以上数据能正常调用(一次按钮事件,连续调用二次),新增也没有问题。主要问题表现为:
按MS官网解释如下:
WCF 数据服务是无状态的,但 DataServiceContext 却不是。 在交互之间将保持客户端上的状态,以便支持更新管理这样的功能。 此类以及表示数据服务的特定 HTTP 请求的 DataServiceQuery 类是客户端库中两个主要的类。
按上面解释:DataServiceContext 是有状态的,但我二次调用,通过Fiddler4监控及Sql server Profiler监控结果为表现下面二种情况:
1.Fiddler 里第一次调用,会出现二次请求,第一次为<title>401 - 未授权: 由于凭据无效,访问被拒绝。</title> ,紧跟着 第二次请求,能获取数据。 所以上面代码结果为一共四次。二次正确的结果,HTTP里COOKIE也不一样的。
2.Profiler 每一次调用都会调用membership 进行用户验证,再执行我需要执行的SQL语句。二次调用会进行二次用户验证。
DataServiceContext 如何通过一个SESSION进行处理?
服务器是这么配置的吧:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
客户端使用 SendingRequest 事件,在发送请求前手动添加 Cookie。
问题我没看到哪里有获取COOKIE的地方,请指教
@greystar: 先用 HttpWebRequest 请求登录页面得到 Cookie,然后保存在你客户端的应用程序域中(比如用一个静态变量),最佳实践是使用 Principal 保存,在客户端自定义 IIdentity 实现,可以叫着 ClientFormsIdentity,将 Cookie 保存在里面,登录成功后从 HttpWebResponse 中得到 Cookie 后创建 ClientFormsIdentity,然后赋值给当前应用程序域的 Principal 。
string cookie = null;
void dataSvc_ReceivingResponse(object sender, ReceivingResponseEventArgs e) {
if (cookie == null)
{
cookie = e.ResponseMessage.Headers("Set-Cookie");
}
}
void dataSvc_SendingRequest(object sender, SendingRequestEventArgs e) {
if(cookie!=null)
{
e.Request.Headers.Add("Set-Cookie", cookie);
}
}
将第一次请求后的COOKIE放到第二次请求中,结果一样,
@greystar: 你也会抓请求,如果两次请求使用的是相同的 Cookie,然后服务器还是要返回 401 的话,这是不是说明服务器本身就设置为每次请求必须先认证?这个很好测试啊,你用 Fiddler 模拟请求,先调用 Logon.aspx,然后再模拟一个请求,把 Logon.aspx 返回的 Cookie 添加到 Request 中,你看看返回啥?
@Launcher:
dataSvc.Credentials = new NetworkCredential("user", "pwd"); form认证用户名及密码
本身服务类是带凭证的。
我现在不是不能访问,我是要搞明白为什么这个带状态的服务类,二次请求服务之间会有四次HTTP请求,同时COOKIE不一样。
我将第一次成功的COOKIE设给第二次请求,无效果。
@greystar: 凭据(Credentials)跟令牌(Token)是两个含义,这个你能明白吧!客户端提交凭据去服务器换取令牌,以后每次请求客户端可以只携带令牌。
"我将第一次成功的COOKIE设给第二次请求"->抓取请求了吗?第二次请求的 Cookie 设置了吗?知道 HTTP Request Header 中的 Cookie 的标头是啥吗?
e.Request.Headers.Add("Set-Cookie", cookie); ——你写错了知道不,应该是 e.Request.Headers.Add("Cookie", cookie);
Set-Cookie 是服务器给客户端响应中写入的,客户端携带 Cookie 应该使用 “Cookie:”标头。
@Launcher:
我找到这个,正在研究,多谢你给我的思路。
@Launcher:
这个我改过了。COOKIE可以估持一致,但 实际执行情况无变化,二次调用,四次请求,多一次数据库验证
@greystar: 把你第二次请求的 Headers 贴出来。
@greystar: 通常应该这么截图:
按照你的描述,你的请求中应该有 Cookie: xxxxx,但是在截图的下半部分应该是以 HTTP/1.1 401 开头的。
@Launcher:
@greystar: 你截图的第二个 ProjectDocuments HTTP 200 的截图呢?
@greystar: 在 web.config 中将 sessionState 的 mode 设置为 off.
@Launcher: 谢谢 我下午试下
@greystar: 然后你应该在 Logon.aspx 或者 AccountController.Logon 中验证客户端凭据并设置 cookie 。在 Application_authenticated 中验证客户端 cookie,没有就重定向到 logon.
@Launcher:
这种说法不太符合我的想法。
目前的ODATA服务应该是一个标准对外服务,理论上不需要再改动任何配置,此服务由Lightswitch工具生成,并且开发了相应的SL及HTML客户端。二个客户端都不存在上述不同SESSION及数据库每次验证问题。
我现在使用WPF自己开发一个客户端,主要问题,我想还是应该在DataServiceContext的配置,按微软MSND上说法,应该是会保持会话的。我通过设置Credentials可以解决自动登录问题,但现在表现的是一次调用一次会话。
查看国外的一些资料,基本都是设置Credentials即可。
服务器不存在Logon.aspx 或者 AccountController.Logon ,也不允许再行修改,因为本身客户端需要运行。
@greystar: 你把 SL 也发那四个请求的包抓取截图来看看。
@Launcher:
@Launcher:
这个程序的登录是专用的SVC,以后不会再用到。后续程序都是ApplicationData.SVC .
我试着调登录的SVC,但这个格式是 msbin1 ,不知道是里面格式是如何定义的,写不进流里。
@greystar: 你是不是发现了你这两幅截图,跟你之前的四幅截图的请求、响应的"Set-Cookie"和“Cookie”标头是不一样的?我现在是在教你“阅读理解”,注意看响应:
Set-Cookie:docManager=xxxxxxxxxxxxxxxxxxxxxxxxx // 这个才是服务器验证后颁发给客户端的 Token。
而你之前截图是这样的:
Set-Cookie:ASP.NET_SessionId=xxxxxxxxxxxx
这说明后一个响应是没有经过认证的,因为没有 Cookie 被设置,只有一个 ASP.NET 会话的标识(会话跟 Cookie 是两回事,这个你能明白吗?)。
然后你先做个 Asp.Net 网站,把使用 Forms Authentication 机制的请求、响应流程给搞明白了再来提问。因为我特别怕你说,“这种说法不太符合我的想法”,“查看国外的一些资料,基本都是设置Credentials即可” 这些话,感觉就像路标指示左转,你非要右转,太危险了。