C# Selenium AADSTS90100: login parameter is empty or not valid - selenium-webdriver

I'm creating a method for logging in to MS Dynamics 365 and get the error below when RUN the test:
AADSTS90100: login parameter is empty or not valid.
Here is my code:
public void Login(SecureString login, SecureString password)
{
_driver.Url = "https://{domain}.crm4.dynamics.com/";
_driver.WaitForPageToLoad(TimeSpan.FromSeconds(10));
var userNameInput = _driver.WaitUntilAvailable(By.CssSelector("input[type = 'email']"),
TimeSpan.FromSeconds(10));
userNameInput.SendKeys(login.ToUnsecureString());
var submitButton = _driver.WaitUntilClickable(By.CssSelector("input[type = 'submit'][value =
'Next']"), TimeSpan.FromSeconds(10));
submitButton.Click();
//userNameInput.SendKeys(Keys.Enter);
// following actions
}
I also tried sending the Enter key and Submit() method but no luck.
Interesting thing - I cannot reproduce the issue manually or when DEBUG the test. The error appears only in the RUN mode of the test.
I compared URLs in RUN and DEBUG modes and there is not any difference.
I spent 3 hours in Google but didn't find a solution.
It should be mentioned, that I'm not an experienced dev. So can miss or don't understand something.
Some ideas?

I've found the root cause.
Actually, the issue occurs not after submitButton.Click(); but after another action which is not provided here, since the error message is a bit confusing.
The thing is we used EasyRepro framework in our solution and getting rid of it now since it's not been supported for more than a year now.
If we take a look at EasyRepro login logic, there is such a method:
private static void EnterPassword(IWebDriver driver, SecureString password)
{
var input =
driver.FindElement(By.XPath(Elements.Xpath[Reference.Login.LoginPassword]));
input.SendKeys(password.ToUnsecureString());
input.Submit();
}
And the error is caused by input.Submit(); line. I just copied it in my new method.
It seems like the method submits the whole form before the login has time to be written somewhere.
So, I simply changed that to this one:
private bool EnterPassword(string password)
{
var passwordInput = _driver.FindElement(By.CssSelector("input[type =
'password']"));
passwordInput.SendKeys(password);
var submitButton = _driver.WaitUntilClickable(By.CssSelector("input[type =
'submit'][value = 'Sign in']"),
_defaultWait);
submitButton.Click();
var staySignedInDialog = _driver.WaitUntilAvailable(By.XPath("//div[contains(text(), 'Stay signed
in?')]"), _defaultWait);
return staySignedInDialog != null;
}
Hope will be useful for someone in the future.

Related

App Certification fails because of PreLaunch Test

When I run the App Certification on my Template 10 based app, I get the following error:
Error Found: The app prelaunch validation detected the following errors:◦The app failed prelaunch test - 49581RisingSoundMedia.ElectionCentral_1.1.7.0_x64__xrbjpqg44kdgm.
•Impact if not fixed: The app will take a longer time to launch, even when prelaunch is enabled.
•How to fix: In the OnLaunched method implementation of the app, ensure you handle the LaunchActivatedEventArgs.PreLaunch option to be prelaunch event aware.
Obviously I can't override the OnLaunched even with Template 10 because the Bootstrap class seals it.
I tried overriding the OnPreLaunchAsync and setting continueStartup = false; but it did not fix the problem.
Any ideas?
This seems to be a known issue with Windows App Cert Kit: https://developer.microsoft.com/en-us/windows/develop/app-certification-kit
"The App Prelaunch Validation test will fail ig you run on a version of Windows-10 released before version 1607(Windows Anniversary Edition). Note that this test is not run as part of the final certification for Windows Store submissions"
Resolution: To ensure the results to this test pass, test with Windows-10 SDK Version (14393) running on Windows-10 Anniversary Edition.
Turns out that I was able to publish to the store, and it passed certification even though it failed the local Windows App Cert Kit locally.
Yes i had this problem, first have you updated to the lastest version of Template 10 (1.1.4): https://www.nuget.org/packages/template10
Next what I had to do was move all of my code that was in OnInitializeAsync and OnStartAsync that was in app.xaml.cs into the App().
You need to keep OnInitializeAsync and OnStartAsync as lean as possible, you should keep only the essential Template10 code in them and add your specific code in App().
public override Task OnInitializeAsync(IActivatedEventArgs args)
{
// content may already be shell when resuming
if ((Window.Current.Content as ModalDialog) == null)
{
// setup hamburger shell
var nav = NavigationServiceFactory(BackButton.Attach, ExistingContent.Include);
Window.Current.Content = new ModalDialog
{
DisableBackButtonWhenModal = true,
Content = new Shell(nav),
ModalContent = new Views.Busy(),
};
}
return Task.CompletedTask;
}
public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
NavigationService.Navigate(typeof(MainView));
return Task.CompletedTask;
}
In App() I added all my my initialization methods for my app so my App() looks liek this:
public App()
{
Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
WindowsCollectors.Metadata |
WindowsCollectors.UnhandledException |
WindowsCollectors.PageView |
WindowsCollectors.Session
);
this.InitializeComponent();
var element = new ViewModelLocator();
//Template10.Services.LoggingService.LoggingService.Enabled = true;
//Template 10 stuff
// DOCS: https://github.com/Windows-XAML/Template10/wiki/Docs-%7C-Cache
CacheMaxDuration = TimeSpan.FromDays(1);
// DOCS: https://github.com/Windows-XAML/Template10/wiki/Docs-%7C-BackButton
ShowShellBackButton = SettingsService.Instance.UseShellBackButton;
// DOCS: https://github.com/Windows-XAML/Template10/wiki/Docs-%7C-SplashScreen
SplashFactory = (e) => new Views.Splash(e);
//My code here
ApiRoot.Instance.Init();
InitDeviceTypeAndResource();
InitApiLanguage();
InitAppLanguage();
InitABCRatings();
//For updating Tiles
RegisterBackgroundTask();
}
I hope that this helps you out!

Pass byte array from WPF to WebApi

tl;dr What is the best way to pass binary data (up to 1MBish) from a WPF application to a WebAPI service method?
I'm currently trying to pass binary data from a WPF application to a WebAPI web service, with variable results. Small files (< 100k) generally work fine, but any larger and the odds of success reduce.
A standard OpenFileDialog, and then File.ReadAllBytes pass the byte[] parameter into the client method in WPF. This always succeeds, and I then post the data to WebAPI via a PostAsync call and a ByteArrayContent parameter.
Is this the correct way to do this? I started off with a PostJSONAsync call, and passed the byte[] into that, but thought the ByteArrayContent seemed more appropriate, but neither work reliably.
Client Method in WPF
public static async Task<bool> UploadFirmwareMCU(int productTestId, byte[] mcuFirmware)
{
string url = string.Format("productTest/{0}/mcuFirmware", productTestId);
ByteArrayContent bytesContent = new ByteArrayContent(mcuFirmware);
HttpResponseMessage response = await GetClient().PostAsync(url, bytesContent);
....
}
WebAPI Method
[HttpPost]
[Route("api/productTest/{productTestId}/mcuFirmware")]
public async Task<bool> UploadMcuFirmware(int productTestId)
{
bool result = false;
try
{
Byte[] mcuFirmwareBytes = await Request.Content.ReadAsByteArrayAsync();
....
}
Web Config Settings
AFAIK these limits in web.config should be sufficient to allow 1MB files through to the service?
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
<httpRuntime targetFramework="4.5" maxRequestLength="2097152"/>
I receive errors in WebAPI when calling ReadAsByteArrayAsync(). These vary, possibly due to the app pool in IIS Express having crashed / getting into a bad state, but they include the following (None of which have lead to any promising leads via google):
Specified argument was out of the range of valid values. Parameter name: offset
at System.Web.HttpInputStream.Seek(Int64 offset, SeekOrigin origin)\r\n
at System.Web.HttpInputStream.set_Position(Int64 value)\r\n at System.Web.Http.WebHost.SeekableBufferedRequestStream.SwapToSeekableStream()\r\n at System.Web.Http.WebHost.Seek
OR
Message = "An error occurred while communicating with the remote host. The error code is 0x800703E5."
InnerException = {"Overlapped I/O operation is in progress. (Exception from HRESULT: 0x800703E5)"}
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)\r\n
at System.Web.Hosting.IIS7WorkerRequest.ReadEntityCoreSync(Byte[] buffer, Int32 offset, Int32 size)\r\n
at System.Web.Hosting.IIS7WorkerRequ...
Initially I thought this was most likely down to IIS Express limitations (running on Windows 7 on my dev pc) but we've had the same issues on a staging server running Server 2012.
Any advice on how I might get this working would be great, or even just a basic example of uploading files to WebAPI from WPF would be great, as most of the code I've found out there relates to uploading files from multipart forms web pages.
Many thanks in advance for any help.
tl;dr It was a separate part of our code in the WebApi service that was causing it to go wrong, duh!
Ah, well, this is embarrassing.
It turns out our problem was down to a Request Logger class we'd registered in WebApiConfig.Register(HttpConfiguration config), and that I'd forgotten about.
It was reading the request content via async as StringContent, and then attempting to log it to the database in an ncarchar(max) field. This itself is probably OK, but I'm guessing all the weird problems started occurring when the LoggingHandler as well as the main WebApi controller, were both trying to access the Request content via async?
Removing the LoggingHandler fixed the problem immediately, and we're now able to upload files of up to 100MB without any problems. To fix it more permanently, I guess I rewrite of the LoggingHandler is required to set a limit on the maximum content size it tries to log / to ignore certain content types.
It's doubtful, but I hope this may be of use for someone one day!
public class LoggingHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LogRequest(request);
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
// ToDo: Decide if/when we need to log responses
// LogResponse(response);
return response;
}, cancellationToken);
}
private void LogRequest(HttpRequestMessage request)
{
(request.Content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
{
try
{
var callerId = CallerId(request);
var callerName = CallerName(request);
// Log request
LogEntry logEntry = new LogEntry
{
TimeStamp = DateTime.Now,
HttpVerb = request.Method.ToString(),
Uri = request.RequestUri.ToString(),
CorrelationId = request.GetCorrelationId(),
CallerId = callerId,
CallerName = callerName,
Controller = ControllerName(request),
Header = request.Headers.ToString(),
Body = x.Result
};
...........

Authenticate user in WinForms (Nothing to do with ASP.Net)

Note: Cross-posted to ServerFault, based on comments.
Intro
I need to password protect some actions in my application, such as loading/saving files, clicking check-boxes, etc. This is a standard C# .Net 4.0, WinForms application which will run on Windows 7 in a corporate network.
I was about to roll my own very basic system (read obfuscation with wide open backdoors) with a text file of users/passwords/permissions (hashed and salted) until after some searching I found what looks like a
tantalizingly simple approach , but I'm having trouble finding a good tutorial on Roles that isn't about ASP.NET.
Question
So does anyone know of one or more tutorials that show me how to:
Create a Windows User/Group and give that User/Group a Role or Permission.
Note that I'm testing this from my company's networked laptop, but will deploy it on the customer's corporate network (Not sure if this is an issue, or how tricky this will get).
Create winforms/console app sample with even just a single method that prints "Hello World" if I'm authenticated or throws an exception if I'm not?
I've never done Network Admin or anything related and I keep reading about Active Directory and Local Users Vs Networked Users... I was hoping for an approach where I could build to an Interface and just ask Windows if the current user has permission ABC and not care too much about how Windows figured that out. Then I can make a concrete implementation for each Local/Network/ActiveDirectory/etc. use case as required (or if required... as I don't even know that right now).
Background
- read if interested, but not required to answer question
Just to make sure I'm going in the right direction here, basically I need/want to test this on my development PC to make sure it's going to have a good end-user experience for my customer. The problem is that currently they run an Auto-login script for each computer that runs my application and there are several different operators that use my application throughout the day. The customer wants password protection on certain features of my app and only provide that to certain operators. I have no problem fitting this in, as I've expected the request for a while, I just haven't ever programmed authentication before.
I think it's worthwhile to convince my customer to give each operator their own network account and assign whatever permissions they want to that operator or group, in case they need to fire somebody, change permissions, etc. It also means I just open several options for them and they can group those permissions however they see fit based on internal corporate policies, which I really shouldn't have to be worried about (but will be if I have to roll my own, as they're IT department knows almost nothing of my application).
From what I can tell it also makes my life a lot easier by not having to deal with hashing passwords and encryption, etc. and just handle which Role is required to click this or that button.
First of all, you'd have to determine, if you really want a simple role-based-authentication (you may want to read: http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/)
If you're sure it's absolutely sufficient, you're already on the right way with the SO link you provided in your question. It's kind of confusing that there is no support of 'roles' by default in Windows, but there are groups. Groups can be local or remote (e.g. ActiveDirectory), so an admin could assign users to certain groups, that are specific for your application (for an example look here: http://msdn.microsoft.com/en-us/library/ms731200(v=vs.110).aspx)
One key is: You have to prepare your application's central principal, hence fill it with roles, supported for the current user.
Therefore, On the very startup of your application you then check the current active user and set your application wide principal and role(s). This may look like this (just a very simple example):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Security.Principal;
using System.Text;
using System.Threading;
namespace WindowsPrincipalTrial
{
public class Program
{
// you could also move these definitions to a config file
private static IDictionary<string, string> _groupRoleMappings = new Dictionary<string, string>()
{
{"MYAPPUSERGRP", MyRoles.Standard},
{"MYAPPSUPPORTGRP", MyRoles.Extended},
{"MYAPPADMINGRP", MyRoles.Admin},
};
private static void Main(string[] args)
{
var windowsId = WindowsIdentity.GetCurrent();
if (windowsId != null)
{
var allRoleNames = getGroupCorrespondingRoles(windowsId);
var newPrincipal = new GenericPrincipal(windowsId, allRoleNames);
Thread.CurrentPrincipal = newPrincipal;
}
else
{
throw new NotSupportedException("There must be a logged on Windows User.");
}
}
private static string[] getGroupCorrespondingRoles(WindowsIdentity id)
{
// you also could do this more elegant with LINQ
var allMappedRoleNames = new List<string>();
string roleName;
foreach (var grp in id.Groups)
{
var groupName = grp.Translate(typeof(NTAccount)).Value.ToUpper();
if (_groupRoleMappings.TryGetValue(groupName, out roleName))
{
allMappedRoleNames.Add(roleName);
}
}
return allMappedRoleNames.ToArray();
}
}
public static class MyRoles
{
public const string Standard = "standard_role";
public const string Extended = "extended_role";
public const string Admin = "admin_role";
}
}
Then your Application-Principal is set up.
Now you could check access in your code like this:
public void DoSomethingSpecial()
{
if (Thread.CurrentPrincipal.IsInRole(MyRoles.Extended))
{
// do your stuff
}
else
{
// maybe display an error
}
}
Or more drastically:
public void DoSomethingCritical()
{
var adminPermission = new PrincipalPermission(null, MyRoles.Admin);
adminPermission.Demand();
// do stuff
}
what is possible even declarative, as known from ASP.NET:
[PrincipalPermission(SecurityAction.Demand, Role=MyRoles.Admin)]
public void DoSomethingMoreCritical()
{
// do stuff
}
The ugly thing with the latter two examples is, that they throw exceptions, when the right role isn't hit.
So the mapping between roles and groups you have to do quite at the start of your app, according to the systems you want to use (local groups, AD groups, LDAP groups etc.).
If you, however, prefer authentication with actions and roles, after all, have a look at Windows Identity Foundation and Claims Based Authorization! There are already some ready-to-use frameworks out there (e.g. https://github.com/thinktecture/Thinktecture.IdentityModel).
UPDATE:
When it comes to activity based and thereby claims based authorization, I will try in short, how you could achieve it, by using Thinktecture's IdentityModel.
Generally that approach still uses roles internally, but has a kind of translation layer in between. Thinktecture already encapsulates many things needed. Authorization checks in code are then done via claim permissions. They are technically kind of request for an access to a certain resource. For the sake of simplicity I limit my example for actions only, by using one single default resource (since ClaimPermission doesn't accept an empty resource).
If you want to use action#resource pairs, you'd have to modify the code respectively.
At first you need a ClaimsAuthorizationManager
public class MyClaimsAuthorizationManager : ClaimsAuthorizationManager
{
private IActivityRoleMapper _actionToRolesMapper;
public MyClaimsAuthorizationManager(IActivityRoleMapper mapper)
{
_actionToRolesMapper = mapper;
}
public override bool CheckAccess(AuthorizationContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
try
{
var action = getActionNameFromAuthorizationContext(context);
var sufficientRoles = _actionToRolesMapper.GetRolesForAction(action)
.Select(roleName => roleName.ToUpper());
var principal = context.Principal;
return CheckAccessInternal(sufficientRoles, principal);
}
catch (Exception ex)
{
return false;
}
}
protected virtual bool CheckAccessInternal(IEnumerable<string> roleNamesInUpperCase, IClaimsPrincipal principal)
{
var result = principal.Identities.Any(identity =>
identity.Claims
.Where(claim => claim.ClaimType.Equals(identity.RoleClaimType))
.Select(roleClaim => roleClaim.Value.ToUpper())
.Any(roleName => roleNamesInUpperCase.Contains(roleName)));
return result;
}
// I'm ignoring resources here, modify this, if you need'em
private string getActionNameFromAuthorizationContext(AuthorizationContext context)
{
return context.Action
.Where(claim => claim.ClaimType.Equals(ClaimPermission.ActionType))
.Select(claim => claim.Value)
.FirstOrDefault();
}
}
As you may have guessed, IActivityRoleMapper is an interface for a class, that returns the names of all roles, that include permission for a given action.
This class is very individual and I guess you'll find your way implementing it, because it's not the point here. You could do it by hardcoding, loading from xml or from a database. Also you would have to change/extend it, if you wanted to you action#resource pairs for permission requests.
Then you'd have to change the code in main() method to:
using Thinktecture.IdentityModel;
using Thinktecture.IdentityModel.Claims;
using Microsoft.IdentityModel.Web;
private static void Main(string[] args)
{
var windowsId = WindowsIdentity.GetCurrent();
if (windowsId != null)
{
var rolesAsClaims = getGroupCorrespondingRoles(windowsId)
.Select(role => new Claim(ClaimTypes.Role, role))
.ToList();
// just if you want, remember the username
rolesAsClaims.Add(new Claim(ClaimTypes.Name, windowsId.Name));
var newId = new ClaimsIdentity(rolesAsClaims, null, ClaimTypes.Name, ClaimTypes.Role);
var newPrincipal = new ClaimsPrincipal(new ClaimsIdentity[] { newId });
AppDomain.CurrentDomain.SetThreadPrincipal(newPrincipal);
var roleMapper = new ActivityRoleMapper(); // you have to implement
// register your own authorization manager, so IdentityModel will use it per default
FederatedAuthentication.ServiceConfiguration.ClaimsAuthorizationManager = new MyClaimsAuthorizationManager(roleMapper);
}
else
{
throw new NotSupportedException("There must be a logged on Windows User.");
}
}
Finally you can check access this way:
public const string EmptyResource = "myapplication";
public void DoSomethingRestricted()
{
if (!ClaimPermission.CheckAccess("something_restricted", EmptyResource))
{
// error here
}
else
{
// do your really phat stuff here
}
}
Or again, with exceptions:
private static ClaimPermission RestrictedActionPermission = new ClaimPermission(EmptyResource, "something_restricted");
public void DoSomethingRestrictedDemand()
{
RestrictedActionPermission.Demand();
// play up, from here!
}
Declarative:
[ClaimPermission(SecurityAction.Demand, Operation = "something_restricted", Resource = EmptyResource)]
public void DoSomethingRestrictedDemand2()
{
// dostuff
}
Hope this helps.

LDAP bind to ActiveDirectory succeeds when user is locked out, under some conditions

I'm testing the behavior of the .net LDAP client when a bad password is provided enough times to trigger a lockout.
I see this odd behavior: it seems that if the process successfully connected at any time, then it is able to re-connect even after purposefully triggering a lockout.
Here's a shorthand version of my binding method:
private DirectoryEntry Bind(string userId, string password)
{
var entry = new DirectoryEntry(BasePath, userId, password);
// If the password is bad, the attempt to access entry.NativeObject throws an exception.
var obj = entry.NativeObject; // causes the bind to occur
return entry;
}
My test proceeds as follows:
private void TestLockout()
{
// attempt with bad pw enough times to trigger a lockout.
for (int i=0; i < 5; i++)
{
try
{
// i.ToString() is a purposefully bad pw
Bind("testuser", i.ToString());
}
catch
{
}
}
// Now make sure that an attempt with a good pw fails due to lockout
var bindSuccess = true;
try
{
Bind("testuser", "correctpassword");
}
catch
{
bindSuccess = false;
}
// the output should be "false"
Console.WriteLine("Bind result is " + bindSuccess.ToString();
}
This works fine as is. However, if a call to Bind() with a good password precedes the test, I get different results.
IOW, this:
Bind("testuser", "correctpassword"); // succeeds
TestLockout(); // does not give the correct result
The following happens.
a) TestLockout produces incorrect output, because the final Bind succeeds and it should not.
b) Yet, I know that the user was locked out, because of subsequent inspection.
So it appears that some component is tracking whether the current process ever connected successfully. I need to have a way to clear this condition. This authentication code will be executing in a long-running service process and it is not acceptable to authenticate a user when they are really locked out.
This is related to the fact that DirectoryEntry is using ADSI. ADSI has internal LDAP connection pool built based on the BasePath, Username and Password.
If you tried to bind with the correct password before the account was locked out, an LDAP connection was successfully made using that correct password and cached in the connection pool. Then, you made your account locked out and tried to bind to the Active Directory using the same BasePath, Username and Password. DirectoryEntry at this time will not establish a new LDAP connection but reuse the previous one. You can prove that by looking at the network trace.
To fix it, you can dispose your DirectoryEntry when you don't need it. Once your DirectoryEntry is disposed, ADSI should be smart enough to close the LDAP connection that it no longer requires. In your sample code, it looks like you never need it again. So, this should fix the problem.
private void Bind(string userId, string password)
{
using (var entry = new DirectoryEntry(BasePath, userId, password))
{
// If the password is bad, the attempt to access entry.NativeObject throws an exception.
var obj = entry.NativeObject; // causes the bind to occur
}
}

Consuming WCF Data Services Service Operator (WebGet) async from Silverlight

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

Resources