Get a list of groups that Azure AD user belongs to in claims for .Net Core - .net-core

I am trying to get the list of groups in Azure AD user belongs to in .Net Core with token generated in the "implicit flow". There is no group information.
I am using "implicit flow" as mentioned in the following link:
.NET Core and Azure Active Directory integration
The following shows how to do it in the .NET Framework but .NET Core don't have the 'ActiveDirectoryClient' class.
Get a list of groups that Azure AD user belongs to in claims
Any Help is much appreciated!
derek

You could firstly set the groupMembershipClaims property to SecurityGroup in manifest , then get the groups list in asp.net core after login :
var groups = User.Claims.Where(c => c.Type == "groups").ToList();
Update :
Then you could call Azure AD Graph api to get the group information . Firstly refer to code sample :https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore
In .net core app , you could get the group object id and call graph api :
https://graph.windows.net/myorganization/groups/<objectid>?api-version=1.6
You could set Read all groups delegated permission for Windows Azure Active Directory in Required permissions blade of your app . Then try below code to get the group name :
try
{
var groups = User.Claims.Where(c => c.Type == "groups").ToList();
string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
ClientCredential credential = new ClientCredential(Startup.ClientId, Startup.ClientSecret);
result = await authContext.AcquireTokenSilentAsync(Startup.GraphResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
//
// Retrieve the group information.
//
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://graph.windows.net/myorganization/groups/"+ groups[1].Value + "?api-version=1.6" );
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
List<Dictionary<String, String>> responseElements = new List<Dictionary<String, String>>();
JsonSerializerSettings settings = new JsonSerializerSettings();
String responseString = await response.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<RootObject>(responseString);
var groupName = model.displayName;
}
else
{
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
}
}
}
catch (Exception ee)
{
}
Group entity below is for your reference :
public class RootObject
{
public string objectType { get; set; }
public string objectId { get; set; }
public object deletionTimestamp { get; set; }
public string description { get; set; }
public object dirSyncEnabled { get; set; }
public string displayName { get; set; }
public object mail { get; set; }
public string mailNickname { get; set; }
public bool mailEnabled { get; set; }
public bool securityEnabled { get; set; }
}

Related

Integration Testing Forms with Nested Objects

I am using .NET Core with Boilerplate. I'm trying to unit test some new forms that require that I have nested objects with properties. The Integration Tests use AbpAspNetCoreIntegratedTestBase<Startup> which uses an instance of both HttpClient and TestServer. The client has various types of methods at its disposal. There are GetAsync, PostAsync, SendSync and PutAsync methods just to name a few.
I thought I had gotten comfortable with some of the methods and helper methods in this frame work and have been successful thus far. However, I have a form with an Model called Vendor, the Vendor has an Address Model as part of the view model. This is so I can reuse the Address View Model with other items in the application that also require Address(es).
One of the helpers that is used with BoilerPlate is GetUrl<TController>(string actionName, object queryStringParamsAsAnonymousObject) Since this is a Post from a form I'm attempting to use public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content) No matter what I'm attempting to do, I'm getting a 400 Bad Request response and my test fails before it even gets inside the controller method. I'm at a loss of how to handle this.
Here are my Models:
VendorViewModel:
[AutoMap(typeof(Domains.Vendor))]
public class VendorViewModel : BaseViewModelEntity
{
[Required]
public string Name { get; set; }
[Required]
public string PointOfContact { get; set; }
[Required]
public string Email { get; set; }
[Required]
public int AddressId { get; set; }
//[Required]
//public string Address1 { get; set; }
//public string Address2 { get; set; }
//public string Address3 { get; set; }
//[Required]
//public string City { get; set; }
//[Required]
//public int State { get; set; }
//[Required]
//public string Zip { get; set; }
//[Required]
//public string Phone { get; set; }
//public string Fax { get; set; }
public AddressViewModel VendorAddress { get; set; }
public VendorViewModel()
{
VendorAddress = new AddressViewModel();
}
public VendorViewModel(VendorDto vendor)
{
Id = vendor.Id;
Name = vendor.Name;
IsActive = vendor.IsActive;
PointOfContact = vendor.PointOfContact;
Email = vendor.Email;
AddressId = vendor.AddressId;
CreatorUserId = vendor.CreatorUserId;
CreationTime = vendor.CreationTime;
DeleterUserId = vendor.DeleterUserId;
DeletionTime = vendor.DeletionTime;
LastModificationTime = vendor.LastModificationTime;
LastModifierUserId = vendor.LastModifierUserId;
//Address1 = vendor.Address.Address1;
//Address2 = vendor.Address.Address2;
//Address3 = vendor.Address.Address3;
//City = vendor.Address.City;
//State = vendor.Address.State;
//Zip = vendor.Address.Zip;
//Phone = vendor.Address.Phone;
//Fax = municipalities.Address.Fax;
VendorAddress = new AddressViewModel()
{
Id = vendor.Address.Id,
Address1 = vendor.Address.Address1,
Address2 = vendor.Address.Address2,
Address3 = vendor.Address.Address3,
City = vendor.Address.City,
State = vendor.Address.State,
Zip = vendor.Address.Zip,
Phone = vendor.Address.Phone,
Fax = vendor.Address.Fax,
CreationTime = vendor.Address.CreationTime,
};
}
}
Address View Model:
public class AddressViewModel : BaseViewModelEntity
{
[Required]
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
[Required]
public string City { get; set; }
[Required]
public int State { get; set; }
[Required]
public string Zip { get; set; }
[Required]
public string Phone { get; set; }
public string Fax { get; set; }
public AddressViewModel()
{
}
public AddressViewModel(AddressDto address)
{
Id = address.Id;
Address1 = address.Address1;
Address2 = address.Address2;
Address3 = address.Address3;
City = address.City;
State = address.State;
Zip = address.Zip;
Phone = address.Phone;
Fax = address.Phone;
CreatorUserId = address.CreatorUserId;
CreationTime = address.CreationTime;
DeleterUserId = address.DeleterUserId;
DeletionTime = address.DeletionTime;
LastModificationTime = address.LastModificationTime;
LastModifierUserId = address.LastModifierUserId;
}
}
I have my Test set up with xUnit
//Arrange
//Add Client Headers so User Auth and Permission Checkers work correctly
Client.DefaultRequestHeaders.Add("my-name", "admin");
Client.DefaultRequestHeaders.Add("my-id", "2");
//set up test data
var addressViewModel = new AddressViewModel()
{
Address1 = "123 This Way", City = "Arlington", State = 44, Zip = "76001", Phone = "8175555555",
CreationTime = DateTime.Now
};
var viewModelSave = new VenderViewModel()
{
Name = "Controller Test Name",
PointOfContact = "Tom Jerry",
Email = "Tom.Jerry#yolo.com",
CreationTime = DateTime.Now,
LastModificationTime = null,
IsActive = true,
AddressId = 0,
VendorAddress = addressViewModel
//Address1 = "123 This Way",
//City = "Arlington",
//State = 44,
//Zip = "76001",
//Phone = "8175555555"
};
/* This is an attempt to use string interpolation to create querystring parameters */
//var rawData =
// $"?Name={viewModelSave.Name}&Id={viewModelSave.Id}&PointOfContat=${viewModelSave.PointOfContact}&Email={viewModelSave.Email}&CreationTime={DateTime.Now}" +
// $"&LastModificationTime=&IsActive={viewModelSave.IsActive}&AddressId={viewModelSave.AddressId}&VendorAddress.Id={viewModelSave.VendorAddress.Id}&VendorAddress.Address1={viewModelSave.VendorAddress.Address1}" +
// $"&VendorAddress.City={viewModelSave.VendorAddress.City}&VendorAddress.State={viewModelSave.VendorAddress.State}&VendorAddress.Zip={viewModelSave.VendorAddress.Zip}&VendorAddress.Phone={viewModelSave.VendorAddress.Phone}" +
// $"&VendorAddress.CreationTime={DateTime.Now}&VendorAddress.IsActive={viewModelSave.VendorAddress.IsActive}";
/*This is an attempt to create a json object that could be serialize into an object as the "queryStringParamsAsAnonymousObject" that can be used in the GetUrl Helper method below */
var rawData = $"{{'Name':'Controller Test Name','PointOfContact':'Tom Jerry', 'Email': 'Tom.Jerry#yolo.com',"
+ "'CreationTime':'" + DateTime.Now + "','LastModificationTime':'','IsActive' : 'true','AddressId':'0','Address.Address1':'123 This Way',"
+ "'Address.City':'Arlington','Address.State':'44','Address.Zip':'76001','Address.Phone':'8175555556','Address.IsActive':'true'}";
var jsonData = JsonConvert.DeserializeObject(rawData);
//Serialize ViewModel to send with Post as part of the HttpContent object
var data = JsonConvert.SerializeObject(viewModelSave);
var vendorAddress = new
{
viewModelSave.vendorAddress.Id,
viewModelSave.vendorAddress.Address1,
viewModelSave.vendorAddress.City,
viewModelSave.vendorAddress.State,
viewModelSave.vendorAddress.Zip,
viewModelSave.vendorAddress.Phone,
viewModelSave.vendorAddress.IsActive,
viewModelSave.vendorAddress.CreationTime
};
//actually get the url from helper method (with various attempts at creating an anonymousObject directly
var url = GetUrl<VendorController>(nameof(VendorController.SaveVendor),
new
{
viewModelSave.Id,
viewModelSave.Name,
viewModelSave.PointOfContact,
viewModelSave.Email,
viewModelSave.CreationTime,
viewModelSave.LastModificationTime,
viewModelSave.IsActive,
viewModelSave.AddressId,
vendorAddress
//VendorAddress_Address1 = vendorAddress.Address1,
//VendorAddress_Id = vendorAddress.Id,
//VendorAddress_City = vendorAddress.City,
//VendorAddress_State = vendorAddress.State,
//VendorAddress_Zip = vendorAddress.Zip,
//VendorAddress_Phone = vendorAddress.Phone,
//VendorAddress_IsActive = vendorAddress.IsActive,
//VendorAddress = new
//{
// viewModelSave.VendorAddress.Id,
// viewModelSave.VendorAddress.Address1,
// viewModelSave.VendorAddress.City,
// viewModelSave.VendorAddress.State,
// viewModelSave.VendorAddress.Zip,
// viewModelSave.VendorAddress.Phone,
// viewModelSave.VendorAddress.IsActive,
// viewModelSave.VendorAddress.CreationTime
//},
//viewModelSave.Address1,
//viewModelSave.City,
//viewModelSave.State,
//viewModelSave.Zip,
//viewModelSave.Phone
}
);
var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
var message = new HttpRequestMessage {
Content = content,
Method = HttpMethod.Post,
RequestUri = new Uri("http://localHost" + url)
};
//Act
var response = await PostResponseAsObjectAsync<AjaxResponse>(url, content);
//Assert
var count = UsingDbContext(context => { return context.Municipalities.Count(x => x.IsActive); });
response.ShouldBeOfType<AjaxResponse>();
response.Result.ShouldNotBeNull();
count.ShouldBe(3);
}
As I attempt to debug what is happening. I've noticed that the VendorAddress properties that are sent via the test request do not match what the actual form post looks like when parsed in Chrome developer tools. In Chrome I see (example:
PointOfContact:"Tom Jerry"
IsActive:True
VendorAddress.Address1:"123 This Way"
VendorAddress.City: "Arlington")
I cannot get my test data into that same format, therefore its not binding correctly to my view models on post, and thus returns a 400 response and fails the test.
I have gotten it to work if I remove the Address View Model all together and put those properties as properties of the VendorViewModel. However, I would run into the same if not similar issue if I'm attempting to save a collection of objects along with the main view model.
I feel like there has to be a way to submit test form data via integration tests with boilerplate. I just need some missing piece to this puzzle.
The Solution that is working for both Post and Send Requests:
.NET Core has a QueryHelper class that will take a dictionary and a uri string and convert it into a url with querystring parameters. QueryHelpers.AddQueryString(string uri, IDictionary queryString) This is part of Microsoft.AspNetCore.WebUtilities.
Using this method I was able to properly prepare my formData. For a Post Request the Test would look like this
//Arrange
//Add Client Headers so User Auth and Permission Checkers work correctly
Client.DefaultRequestHeaders.Add("my-name", "admin");
Client.DefaultRequestHeaders.Add("my-id", "2");
//set up test data
var rawData = new Dictionary<string, string>(){{ "Id", "0"}, {"Name", "Controller Test Name"}, {"PointOfContact", "Tom Jerry"}
, {"Email", "Tom.Jerry#yolo.comy"}, {"CreationTime", $"{DateTime.Now}"}, {"LastModificationTime", ""}, {"IsActive", "true"}, {"AddressId", "0"}
, {"VendorAddress.Id", "0"}, {"VendorAddress.Address1", "123 This Way"}, {"VendorAddress.City", "Arlington"}, {"VendorAddress.State", "44"}, {"VendorAddress.Zip", "76001"}
, {"VendorAddress.Phone", "8175555555"}, {"VendorAddress.Fax", ""}, {"VendorAddress.IsActive", "true"}, {"VendorAddress.CreationTime", $"{DateTime.Now}"}, {"VendorAddress.LastModificationTime", ""}
};
var jsonData = JsonConvert.DeserializeObject(rawData);
//Serialize ViewModel to send with Post as part of the HttpContent object
var data = JsonConvert.SerializeObject(viewModelSave);
//actually get the url from helper method
var url = GetUrl<VendorController>(nameof(VendorController.SaveVendor));
var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
//Act
var response = await PostResponseAsObjectAsync<AjaxResponse>(url, content);
//Assert
var count = UsingDbContext(context => { return context.Municipalities.Count(x => x.IsActive); });
response.ShouldBeOfType<AjaxResponse>();
response.Result.ShouldNotBeNull();
count.ShouldBe(3);
Send Request Test would look like this
//Arrange
//Add Client Headers so User Auth and Permission Checkers work correctly
Client.DefaultRequestHeaders.Add("my-name", "admin");
Client.DefaultRequestHeaders.Add("my-id", "2");
//set up test data
var rawData = new Dictionary<string, string>(){{ "Id", "0"}, {"Name", "Controller Test Name"}, {"PointOfContact", "Tom Jerry"}
, {"Email", "Tom.Jerry#yolo.comy"}, {"CreationTime", $"{DateTime.Now}"}, {"LastModificationTime", ""}, {"IsActive", "true"}, {"AddressId", "0"}
, {"VendorAddress.Id", "0"}, {"VendorAddress.Address1", "123 This Way"}, {"VendorAddress.City", "Arlington"}, {"VendorAddress.State", "44"}, {"VendorAddress.Zip", "76001"}
, {"VendorAddress.Phone", "8175555555"}, {"VendorAddress.Fax", ""}, {"VendorAddress.IsActive", "true"}, {"VendorAddress.CreationTime", $"{DateTime.Now}"}, {"VendorAddress.LastModificationTime", ""}
};
var jsonData = JsonConvert.DeserializeObject(rawData);
//Serialize ViewModel to send with Post as part of the HttpContent object
var data = JsonConvert.SerializeObject(viewModelSave);
//actually get the url from helper method
var url = GetUrl<VendorController>(nameof(VendorController.SaveVendor));
var content = new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded");
var message = new HttpRequestMessage {
Content = content,
Method = HttpMethod.Post,
RequestUri = new Uri("http://localHost" + url)
};
//Act
var response = await SendResponseAsObjectAsync<AjaxResponse>(message);
//Assert
var count = UsingDbContext(context => { return context.Municipalities.Count(x => x.IsActive); });
response.ShouldBeOfType<AjaxResponse>();
response.Result.ShouldNotBeNull();
count.ShouldBe(3);

get user email after Azure AD authentication in xamarin app

I need to get the email adress after the user authentication.
I tried to fid this information in the authenticationResult but I just found the user name .. but not the email.
How can I get this information?
Thanks
Do you want the email on the client-side or the server-side? If it's the server-side, try checking the x-ms-client-principal-name HTTP header value. If it's the client-side, try making an authenticated request to /.auth/me and you should see all the claims, including the user's email in the JSON response.
Since you mentioned in another answer that this is client side, use the InvokeApi<>() method. This is discussed in detail in the book here: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter2/authorization/#obtaining-user-claims
Short version is this code:
List<AppServiceIdentity> identities = null;
public async Task<AppServiceIdentity> GetIdentityAsync()
{
if (client.CurrentUser == null || client.CurrentUser?.MobileServiceAuthenticationToken == null)
{
throw new InvalidOperationException("Not Authenticated");
}
if (identities == null)
{
identities = await client.InvokeApiAsync<List<AppServiceIdentity>>("/.auth/me");
}
if (identities.Count > 0)
return identities[0];
return null;
}
Where AppServiceIdentity is defined like this:
public class AppServiceIdentity
{
[JsonProperty(PropertyName = "id_token")]
public string IdToken { get; set; }
[JsonProperty(PropertyName = "provider_name")]
public string ProviderName { get; set; }
[JsonProperty(PropertyName = "user_id")]
public string UserId { get; set; }
[JsonProperty(PropertyName = "user_claims")]
public List<UserClaim> UserClaims { get; set; }
}
public class UserClaim
{
[JsonProperty(PropertyName = "typ")]
public string Type { get; set; }
[JsonProperty(PropertyName = "val")]
public string Value { get; set; }
}
I don't find the InvokeApiAsync to call it.
are there a token or something like that to find the email ?
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, CloudConstants.ApIbaseUrl + /.auth/me");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _authenticationResult.Token);
try
{
var response = client.SendAsync(request);
if (response.Result.IsSuccessStatusCode)
{
var responseString = response.Result.Content.ReadAsStringAsync();
var profile = JArray.Parse(responseString.Result);
}
}
catch (Exception ee)
{
_dialogService.DisplayAlertAsync("An error has occurred", "Exception message: " + ee.Message, "Dismiss");
}

ASP .NET Web API SaveChangesAsync with Foreign Key Data

I have Customer and Address classes, something like this:
public class Customer
{
[PrimaryKey]
public int Id { get; set; }
public string CustomerName { get; set; }
public int ShippingAddressId { get; set; }
[ForeignKey("ShippingAddressId")]
public Address ShippingAddress { get; set; }
}
public class Address
{
[PrimaryKey]
public int Id { get; set; }
public string City { get; set; }
}
When I call a Web API to update the Customer, I pass an edited Customer object to this method. For example, I edit 2 properties: Customer.CustomerName and Customer.ShippingAddress.City
AuthenticationResult ar = await new AuthHelper().AcquireTokenSilentAsync();
if (ar.Token == null) return false;
using (var json = new StringContent(JsonConvert.SerializeObject(entity), UnicodeEncoding.UTF8, "application/json"))
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Settings.ApiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ar.Token);
using (HttpResponseMessage response = await client.PutAsync("api/" + type.ToString() + "/" + id, json))
{
response.EnsureSuccessStatusCode();
return await InsertOrReplaceResponse(type, response);
}
}
Here is the Web API:
[HttpPut("{id}")]
public async Task<IActionResult> PutCustomer([FromRoute] int id, [FromBody] Customer customer)
{
_context.Entry(customer).State = EntityState.Modified;
await _context.SaveChangesAsync();
return new StatusCodeResult(StatusCodes.Status204NoContent);
}
However, only Customer.CustomerName gets updated. The foreign key data (Customer.ShippingAddress.City) isn't updated in the Address table.
Any idea what I'm doing wrong?
Thanks!
Generally, I would expect the child Address entity to be update as well because you use foreign key association which also should be the default for one-to-one mappings (see here for more details). However, it seems that something is not setup right and you get independent association behavior where you have to manage child entity state yourself. Should be a simple fix in your case:
_context.Entry(customer).State = EntityState.Modified;
_context.Entry(customer.ShippingAddress).State = EntityState.Modified;

How to show the JSON data in asp.net web form

I am Beginner at Asp.net so can anyone plz help me to show the data provided in the below shown JSON Api in Asp.net Step by Step.It be of great help if this is answered.
http://fantasy.premierleague.com/web/api/elements/180/
A good way to use Json in C# is with Json.NET
JSON.NET - Official site will help you work with it.
Example to use it
public class User {
public User(string json) {
JObject jObject = JObject.Parse(json);
JToken jUser = jObject["user"];
name = (string) jUser["name"];
teamname = (string) jUser["teamname"];
email = (string) jUser["email"];
players = jUser["players"].ToArray();
}
public string name { get; set; }
public string teamname { get; set; }
public string email { get; set; }
public Array players { get; set; }
}
// Use
private void Run() {
string json = #"{""user"":{""name"":""asdf"",
""teamname"":""b"",""email"":""c"",""players"":[""1"",""2""]}}";
User user = new User(json);
Console.WriteLine("Name : " + user.name);
Console.WriteLine("Teamname : " + user.teamname);
Console.WriteLine("Email : " + user.email);
Console.WriteLine("Players:");
foreach (var player in user.players)
Console.WriteLine(player);
}

WebAPI Serialization problems when consuming Recurly Rest API which returns XML

I'm new to the ASP.Net Web API. I'm trying to interact with the Recurly REST based API and I am getting errors like below during my ReadAsAsync call which is the point I believe it attempts to serialize the response.
{"Error in line 1 position 73. Expecting element 'account' from namespace 'http://schemas.datacontract.org/2004/07/RecurlyWebApi.Recurly'.. Encountered 'Element' with name 'account', namespace ''. "}
Here is my HttpClient implementation, simplified for brevity:
public class RecurlyClient
{
readonly HttpClient client = new HttpClient();
public RecurlyClient()
{
var config = (RecurlySection)ConfigurationManager.GetSection("recurly");
client.BaseAddress = new Uri(string.Format("https://{0}.recurly.com/v2/", config.Subdomain));
// Add the authentication header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(config.ApiKey)));
// Add an Accept header for XML format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
}
public T Get<T>(string id)
{
var accounts = default(T);
// Make the request and get the response from the service
HttpResponseMessage response = client.GetAsync(string.Concat("accounts/", id)).Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
accounts = response.Content.ReadAsAsync<T>().Result;
}
return accounts;
}
}
And here is my model:
[XmlRoot("account")]
public class Account
{
[XmlAttribute("href")]
public string Href { get; set; }
[XmlElement("account_code")]
public string AccountCode { get; set; }
[XmlElement("state")]
public AccountState State { get; set; }
[XmlElement("username")]
public string Username { get; set; }
[XmlElement("email")]
public string Email { get; set; }
[XmlElement("first_name")]
public string FirstName { get; set; }
[XmlElement("last_name")]
public string LastName { get; set; }
[XmlElement("company_name")]
public string Company { get; set; }
[XmlElement("accept_language")]
public string LanguageCode { get; set; }
[XmlElement("hosted_login_token")]
public string HostedLoginToken { get; set; }
[XmlElement("created_at")]
public DateTime CreatedDate { get; set; }
[XmlElement("address")]
public Address Address { get; set; }
}
And an example of the XML response from the service:
<account href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01">
<adjustments href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/adjustments"/>
<invoices href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/invoices"/>
<subscriptions href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/subscriptions"/>
<transactions href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/transactions"/>
<account_code>SDTEST01</account_code>
<state>active</state>
<username>myusername</username>
<email>simon#example.co.uk</email>
<first_name>First name</first_name>
<last_name>Last name</last_name>
<company_name>My Company Name</company_name>
<vat_number nil="nil"></vat_number>
<address>
<address1>My Address Line 1/address1>
<address2>My Address Line 2</address2>
<city>My City</city>
<state>My State</state>
<zip>PL7 1AB</zip>
<country>GB</country>
<phone>0123456789</phone>
</address>
<accept_language nil="nil"></accept_language>
<hosted_login_token>***</hosted_login_token>
<created_at type="datetime">2013-08-22T15:58:17Z</created_at>
</account>
I think the problem is because by default the DataContractSerializer is being used to deserialize the XML, and by default the DataContractSerializer uses a namespace of namespace http://schemas.datacontract.org/2004/07/Clr.Namespace. (In this case Clr.Namepace is RecurlyWebApi.Recurly.)
Because your XML has attributes, you need to use the XmlSerializer instead of the DataContractSerializer, and you're set up to do this because your account class is decorated with Xml* attributes. However, you have to use an XmlMediaTypeFormatter which is using the XmlSerializer. You can do this by setting a flag on the global XMLFormatter as described on this page:
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
or by supplying a MediaTypeFormatter as a parameter to your ReadAsAsync call:
var xmlFormatter = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xmlFormatter.UseXmlSerializer = true;
accounts = response.ReadAsAsync<T>(xmlFormatter).Result
Not 100% sure of this because this doesn't explain why the first 'account' in your error message is lower case - the DataContractSerializer should ignore the XmlRoot attribute.

Resources