4

Having a lot of problems trying to consume a simple service operator in a WCF Data Service from Silverlight. I've verified the following service operator is working by testing it in the browser:

[WebGet]
public IQueryable<SecurityRole> GetSecurityRolesForUser(string userName) {
  string currentUsername = HttpContext.Current.User.Identity.Name;

  // if username passed in, verify current user is admin and is getting someone else's permissions
  if (!string.IsNullOrEmpty(userName)) {
    if (!SecurityHelper.IsUserAdministrator(currentUsername))
      throw new DataServiceException(401, Properties.Resources.RequiestDeniedInsufficientPermissions);
  } else // else nothing passed in, so get the current user's permissions
    userName = currentUsername;

  return SecurityHelper.GetUserRoles(userName).AsQueryable<SecurityRole>();
}

However no matter how I try using different methods I've found in various online resources, I've been unable to consume the data. I've tried using the BeginExecute() method on boht the DataServiceContext and DataServiceQuery, but I keep getting errors or no data returned in the EndExecute method. I've got to be doing something simple wrong... here's my SL code:

private void InitUserSecurityRoles() {
  MyEntities context = new MyEntities(new Uri("http://localhost:9999/MyService.svc"));
  context.BeginExecute<SecurityRole>(new Uri("http://localhost:9999/MyService.svc/GetSecurityRolesForUser"), OnComplete, context);

  DataServiceQuery<SecurityRole> query = context.CreateQuery<SecurityRole>("GetSecurityRolesForUser");
  query.BeginExecute(OnComplete, query);
}

private void OnComplete(IAsyncResult result) {
  OnDemandEntities context = result.AsyncState as OnDemandEntities;
  var x = context.EndExecute<SecurityRole>(result);
}

Any tips? I'm at a loss right now on how to properly consume a custom service operator from Silverlight (or even sync using my unit test project) from a OData service. I've also verified via Fiddler that I'm passing along the correct authentication stuff as well, even going to far as explicitly set the credentials. Just to be safe, I even removed the logic from the service operator that does the security trimming.

Andrew Connell
  • 4,939
  • 5
  • 30
  • 42
  • What errors do you get? The client side code above seems not correct. The BeginExecute passes the MyEntities context and the other one the query as the async state, but the OnComplete casts it to some class OnDemandEntities which is not used anywhere else. That can't ever work. In the Fiddler - does the server send the right response back to the client? – Vitek Karas MSFT Aug 13 '10 at 07:41
  • Is SecurityRole on of your Entity Collections on the OData service? The Silverlight Data Service Client at one time did support non-entities and still might not. I will have to look into it again with the new release. – Chris Woodruff Aug 13 '10 at 13:09
  • Vitek - the server always responded with what I'd expect to see. When I'd run the same query (http://localhost:9999/MyService.svc/GetSecurityRolesForUser) in the browser I'd see the same results I'd get in Fiddler. THe error I got was: System.InvalidOperationException occurred Message=Error processing response stream. The XML element contains mixed content. – Andrew Connell Aug 13 '10 at 13:27
  • Chris - Yup, SecurityRole is in my collection and it was coming back just fine when requested from the browser. – Andrew Connell Aug 13 '10 at 13:28

1 Answers1

3

Got it working thanks to @kaevans (http://blogs.msdn.com/b/kaevans):

private void InitUserSecurityRoles() {
  DataServiceContext context = new DataServiceContext(new Uri("http://localhost:9999/MyService.svc"));
  context.BeginExecute<SecurityRole>(new Uri("/GetSecurityRolesForUser", UriKind.Relative),
    (result) => {
      SmartDispatcher.BeginInvoke(
        () => {
          var roles = context.EndExecute<SecurityRole>(result);

          UserSecurityRoles = new List<SecurityRole>();
          foreach (var item in roles) {
            UserSecurityRoles.Add(item);
          }
        });
    }, null);
}

I had to create the SmartDispatcher because this is happening in a ViewModel. Otherwise I could have just used the static Dispatcher.BeginInvoke(). Couldn't get the roles variable to insert into my UserSecurityRoles (type List) directly for sone reason using various techniques, so I just dropped down to adding it manually (code isn't called often nor is it a collection exceeding more than 10 items max... most are <5).

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Andrew Connell
  • 4,939
  • 5
  • 30
  • 42
  • Have you tried this with the SharePoint list data services? I'm curious if you have to jump through the same hoops or if it's easier. Seems like it would be similar since they are both OData, but I don't know how different your custom service might be. – Tom Resing Aug 13 '10 at 15:18
  • No... this wasn't a problem with working with the stock entities. I had created a custom service operator (http://msdn.microsoft.com/en-us/library/cc668788.aspx). In the case of SharePoint, the service is already created. For me, this is a non-SharePoint service I was creating. So to answer your question, you wouldn't have this challenge. – Andrew Connell Aug 13 '10 at 18:44