首页 新闻 会员 周边 捐助

关于DataServiceContext 消费Odata问题

1
悬赏园豆:30 [已解决问题] 解决于 2015-08-03 17:20

数据源为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进行处理?

greystar的主页 greystar | 初学一级 | 园豆:193
提问于:2015-07-29 09:57
< >
分享
最佳答案
0

服务器是这么配置的吧:

<authentication mode="Forms">     
  <forms loginUrl="~/Account/LogOn" timeout="2880" />      
</authentication>

客户端使用 SendingRequest 事件,在发送请求前手动添加 Cookie。

https://msdn.microsoft.com/zh-cn/library/system.data.services.client.dataservicecontext.sendingrequest(v=vs.110).aspx

收获园豆:30
Launcher | 高人七级 |园豆:45050 | 2015-07-29 10:12

问题我没看到哪里有获取COOKIE的地方,请指教

greystar | 园豆:193 (初学一级) | 2015-07-29 10:14

@greystar: 先用 HttpWebRequest 请求登录页面得到 Cookie,然后保存在你客户端的应用程序域中(比如用一个静态变量),最佳实践是使用 Principal 保存,在客户端自定义 IIdentity 实现,可以叫着 ClientFormsIdentity,将 Cookie 保存在里面,登录成功后从 HttpWebResponse 中得到 Cookie 后创建 ClientFormsIdentity,然后赋值给当前应用程序域的 Principal 。

Launcher | 园豆:45050 (高人七级) | 2015-07-29 10:26

  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 | 园豆:193 (初学一级) | 2015-07-29 10:27

@greystar: 你也会抓请求,如果两次请求使用的是相同的 Cookie,然后服务器还是要返回 401 的话,这是不是说明服务器本身就设置为每次请求必须先认证?这个很好测试啊,你用 Fiddler 模拟请求,先调用 Logon.aspx,然后再模拟一个请求,把 Logon.aspx 返回的 Cookie 添加到 Request 中,你看看返回啥?

Launcher | 园豆:45050 (高人七级) | 2015-07-29 10:30

@Launcher: 

dataSvc.Credentials = new NetworkCredential("user", "pwd"); form认证用户名及密码

本身服务类是带凭证的。

我现在不是不能访问,我是要搞明白为什么这个带状态的服务类,二次请求服务之间会有四次HTTP请求,同时COOKIE不一样。

我将第一次成功的COOKIE设给第二次请求,无效果。

greystar | 园豆:193 (初学一级) | 2015-07-29 10:35

@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 | 园豆:45050 (高人七级) | 2015-07-29 10:43

@Launcher: 

http://blogs.msdn.com/b/odatateam/archive/2010/07/21/odata-and-authentication-part-7-forms-authentication.aspx

我找到这个,正在研究,多谢你给我的思路。

greystar | 园豆:193 (初学一级) | 2015-07-29 10:45

@Launcher: 

这个我改过了。COOKIE可以估持一致,但 实际执行情况无变化,二次调用,四次请求,多一次数据库验证

greystar | 园豆:193 (初学一级) | 2015-07-29 11:05

@greystar: 把你第二次请求的 Headers 贴出来。

Launcher | 园豆:45050 (高人七级) | 2015-07-29 11:07

@greystar: 通常应该这么截图:

 

按照你的描述,你的请求中应该有 Cookie: xxxxx,但是在截图的下半部分应该是以 HTTP/1.1 401 开头的。

Launcher | 园豆:45050 (高人七级) | 2015-07-29 11:12

@Launcher: 

greystar | 园豆:193 (初学一级) | 2015-07-29 11:18

@greystar: 你截图的第二个 ProjectDocuments HTTP 200 的截图呢?

Launcher | 园豆:45050 (高人七级) | 2015-07-29 11:32

@greystar: 在 web.config 中将 sessionState 的 mode 设置为 off.

Launcher | 园豆:45050 (高人七级) | 2015-07-29 11:48

@Launcher: 谢谢 我下午试下

greystar | 园豆:193 (初学一级) | 2015-07-29 11:51

@greystar: 然后你应该在 Logon.aspx 或者 AccountController.Logon 中验证客户端凭据并设置 cookie 。在 Application_authenticated 中验证客户端 cookie,没有就重定向到 logon.

Launcher | 园豆:45050 (高人七级) | 2015-07-29 11:54

@Launcher: 

这种说法不太符合我的想法。

目前的ODATA服务应该是一个标准对外服务,理论上不需要再改动任何配置,此服务由Lightswitch工具生成,并且开发了相应的SL及HTML客户端。二个客户端都不存在上述不同SESSION及数据库每次验证问题。

我现在使用WPF自己开发一个客户端,主要问题,我想还是应该在DataServiceContext的配置,按微软MSND上说法,应该是会保持会话的。我通过设置Credentials可以解决自动登录问题,但现在表现的是一次调用一次会话。

查看国外的一些资料,基本都是设置Credentials即可。

服务器不存在Logon.aspx 或者 AccountController.Logon ,也不允许再行修改,因为本身客户端需要运行。

greystar | 园豆:193 (初学一级) | 2015-07-29 12:42

@greystar: 你把 SL 也发那四个请求的包抓取截图来看看。

Launcher | 园豆:45050 (高人七级) | 2015-07-29 13:17

@Launcher: 

greystar | 园豆:193 (初学一级) | 2015-07-30 09:28

@Launcher: 

这个程序的登录是专用的SVC,以后不会再用到。后续程序都是ApplicationData.SVC .

我试着调登录的SVC,但这个格式是 msbin1 ,不知道是里面格式是如何定义的,写不进流里。

greystar | 园豆:193 (初学一级) | 2015-07-30 09:33

@greystar: 你是不是发现了你这两幅截图,跟你之前的四幅截图的请求、响应的"Set-Cookie"和“Cookie”标头是不一样的?我现在是在教你“阅读理解”,注意看响应:

Set-Cookie:docManager=xxxxxxxxxxxxxxxxxxxxxxxxx  // 这个才是服务器验证后颁发给客户端的 Token。

而你之前截图是这样的:

Set-Cookie:ASP.NET_SessionId=xxxxxxxxxxxx

这说明后一个响应是没有经过认证的,因为没有 Cookie 被设置,只有一个 ASP.NET 会话的标识(会话跟 Cookie 是两回事,这个你能明白吗?)。

 

然后你先做个 Asp.Net 网站,把使用 Forms Authentication 机制的请求、响应流程给搞明白了再来提问。因为我特别怕你说,“这种说法不太符合我的想法”,“查看国外的一些资料,基本都是设置Credentials即可” 这些话,感觉就像路标指示左转,你非要右转,太危险了。

Launcher | 园豆:45050 (高人七级) | 2015-07-31 09:34
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册