views:

228

answers:

1

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.

+1  A: 

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).

AC
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
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.
AC