ServiceStack's JsConfig.TextCase no long honored in v6.0 - servicestack

We have existing code that worked as desired in ServiceStack v5.13.2, but had unexpected breaking behavior after upgrading to v6.0.0.
Here is our service implementation:
public async Task<object> Get(IsAuthenticated request)
{
var session = await this.GetSessionAsync();
bool isAuth = await AuthUserSessionExtensions.AuthenticateAsync(Request, Request.Dto);
if (!isAuth) throw new UnauthorizedAccessException();
var sanitizedSession = new AuthUserSession()
{
FirstName = session.FirstName,
LastName = session.LastName,
Email = session.Email,
Permissions = session.Permissions,
Roles = session.Roles,
UserName = session.UserName,
};
return sanitizedSession;
}
Originally, we would receive the response back in camelCase, per our JsConfig settings. After upgrading, the AuthUserSession was ALWAYS in PascalCase. Even wrapping a manual serialization in a JsConfig scope and explicitly requesting camelCase, serialization only ever provided Pascal.
Example output post-upgrade:
{
"ReferrerUrl": null,
"Id": null,
"UserAuthId": "5",
"UserAuthName": null,
"UserName": "admin",
"TwitterUserId": null,
}
My only thought is the ServiceStack v6 libraries perform special serialization for AuthUserSession and/or ServiceStack's own POCOs.

A work-around is to create a custom POCO that matches field-for-field the AuthUserSession. Serialization of our own classes works without issue.
public class CustomSession
{
public string UserAuthId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public List<string> Permissions { get; set; }
public List<string> Roles { get; set; }
public string UserName { get; set; }
}
results in the properly serialized output:
{
"userAuthId": "5",
"firstName": "Admin",
"lastName": "Admin",
"email": "admin#",
...

Related

How To Return only Child Model property in wep api response

here Is my Models ,here in my model PK is decorated with Key becoz in EF it must be . But as it is aslo available in base class. if I removed PK from Person it gives error as model has not assign a Key IN EF which is strange to me .
public class Person:TBase
{
[Key]
public long PK { get; set; }
public string NAME { get; set; }
public string ADDRESS { get; set; }
}
public class TBase: Base
{
public virtual long? FKTenant { get; set; }
public virtual bool IsDefault { get; set; }
}
public class Base
{
[Key]
public long PK { get; set; }
public virtual string GlobalID { get; set; }
}
and Controller
[EnableQuery]
public IHttpActionResult Get()
{
try
{
IQueryable<Person> result;
var result = DbContext.Persons.Where(x => x.FKTenant == context.FKTenant).ToList();
return Ok(result);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
i am getting response in postman is
"value": [
{
"#odata.etag": "W/\"bnVsbA==\"",
"PK": 1001,
"NAME": "VIVEK",
"ADDRESS": "DELHI",
"FKTenant":null,
"IsDefault ":null,
"GlobalID ":null
}]
But my Intention to get ouput response as below which should contain onlly name and address
"value": [
{
"#odata.etag": "W/\"bnVsbA==\"",
"NAME": "VIVEK",
"ADDRESS": "DELHI"
}]
Any guide will be appreciable.
You should use a ViewModel
write another class as ViewModel and when you want return object first map to new ViewModel then return it.

ServiceStack Wrapper for Bloomberg OpenFIGI

I need to make the following call to an open API (https://www.openfigi.com/api)
Curl Example:
curl -v -X POST 'https://api.openfigi.com/v1/mapping' \
--header 'Content-Type: text/json' \
--data '[{"idType":"ID_WERTPAPIER","idValue":"851399","exchCode":"US"}]'
Request Format
The request is passed in via HTTP request body. The only supported HTTP verb is POST. Here is a sample request to the API:
[
{"idType":"ID_ISIN","idValue":"US4592001014"},
{"idType":"ID_WERTPAPIER","idValue":"851399","exchCode":"US"},
{"idType":"ID_BB_UNIQUE","idValue":"EQ0010080100001000","currency": "USD"},
{"idType":"ID_SEDOL","idValue":"2005973","micCode":"EDGX", "currency":"USD"}
]
Using ServiceStack Request DTO, how do I make a RequestDto to achieve a call to to the above third party service endpoint.
This is just an exercise of creating DTOs which match the shape of the JSON you want to output and JSON you want to receive. To emit the exact the exact JSON property names you can either use [DataMember] on the Request DTO, or JsConfig.EmitCamelCaseNames = true to tell ServiceStack to serialize properties in camelCase or you can use JsConfig.With() to create a Custom Scope.
I've created a Live example of this in Gistlyn which you can use to experiment against Bloomberg's API.
I've used [DataMember] attribute here as it will work independent of your Json Serialization config. You don't need to do this for the Response DTO because ServiceStack Serializers is case-insensitive.
So to send the Request that matches the shape of that JSON you can use:
[DataContract]
public class Mapping
{
[DataMember(Name="idType")]
public string IdType { get; set; }
[DataMember(Name="idValue")]
public string IdValue { get; set; }
[DataMember(Name="exchCode")]
public string ExchCode { get; set; }
[DataMember(Name="currency")]
public string Currency { get; set; }
[DataMember(Name="micCode")]
public string MicCode { get; set; }
}
You can use ServiceStack's HTTP Utils to easily send requests to 3rd Party APIs, e.g:
var url = "https://api.openfigi.com/v1/mapping";
var json = url.PostJsonToUrl(new[]{
new Mapping { IdType = "ID_ISIN", IdValue = "US4592001014" },
new Mapping { IdType = "ID_WERTPAPIER", IdValue = "851399", ExchCode = "US" },
new Mapping { IdType = "ID_BB_UNIQUE", IdValue = "EQ0010080100001000", Currency = "USD" },
new Mapping { IdType = "ID_SEDOL", IdValue = "2005973", MicCode = "EDGX", Currency = "USD" },
});
Then to receive the response you need to create DTOs which match the shape of the JSON Response which looks like:
public class BloombertResult
{
public string Figi { get; set; }
public string SecurityType { get; set; }
public string MarketSector { get; set; }
public string Ticker { get; set; }
public string Name { get; set; }
public string UniqueId { get; set; }
public string ExchCode { get; set; }
public string ShareClassFIGI { get; set; }
public string CompositeFIGI { get; set; }
public string SecurityType2 { get; set; }
public string SecurityDescription { get; set; }
public string UniqueIdFutOpt { get; set; }
}
public class BloombergResponse
{
public List<BloombertResult> Data { get; set; }
public string Error { get; set; }
}
Which you can just deserialize into a collection of BloombergResponse, e.g:
var response = json.FromJson<BloombergResponse[]>();
Gistlyn will show you a nice human readable preview of each variable by clicking on it in the watch window. Or if you're this in a C# Unit test you can quickly see to populated DTOs with:
response.PrintDump();

ServiceStack issue with object serialization between test method and service

Good day,
We are experiencing an issue with serialization where a request object set with a value for one property ends up being received by the service with the value assigned to a different property. Please see below for more information.
We are using the 3.9.71 version of ServiceStack NuGet packages. The solution is made up of the following projects:
Project.Host: Used for self-hosting ServiceStack and contains Service classes.
Project.DTO: All services DTOs and surrounding classes.
Project.Tests: Contains unit tests.
The problems has been identified to only one class/service, namely MinimalUser and MinimalUserService, which you can see code for both below:
MinimalUser.cs
namespace Project.DTO
{
[Route("/User/{Identity}", "GET")]
[Route("/User/{Username}", "GET")]
[Route("/User/{DisplayName}", "GET")]
public class MinimalUser : IReturn<MinimalUser>
{
#region Properties
public int? Identity { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Language { get; set; }
public string TimeZone { get; set; }
public string Culture { get; set; }
public List<string> Roles { get; set; }
public List<string> Permissions { get; set; }
public DiscUserDetails DiscUserDetails { get; set; }
#endregion
#region Constructors
public MinimalUser() { }
public MinimalUser(UserAuth auth)
{
if (auth != null)
{
this.Identity = auth.Id;
this.Username = auth.UserName;
this.DisplayName = auth.DisplayName;
this.Email = auth.Email;
this.FirstName = auth.FirstName;
this.LastName = auth.LastName;
this.Language = auth.Language;
this.TimeZone = auth.TimeZone;
this.Culture = auth.Culture;
this.Roles = auth.Roles;
this.Permissions = auth.Permissions;
this.DiscUserDetails = auth.Get<DiscUserDetails>();
}
}
#endregion
#region Methods
public static MinimalUser FromUserAuth(UserAuth auth)
{
return auth == null ? new MinimalUser() : new MinimalUser
{
Identity = auth.Id,
Username = auth.UserName,
DisplayName = auth.DisplayName,
Email = auth.Email,
FirstName = auth.FirstName,
LastName = auth.LastName,
Language = auth.Language,
TimeZone = auth.TimeZone,
Culture = auth.Culture,
Roles = auth.Roles,
Permissions = auth.Permissions,
DiscUserDetails = auth.Get<DiscUserDetails>()
};
}
#endregion
}
}
DiscUserDetails.cs
namespace Project.DTO
{
public class DiscUserDetails
{
public int? LocationId { get; set; }
public bool IsActive { get; set; }
public byte NumberOfFailedLoginAttempts { get; set; }
public bool MustChangePasswordAtNextLogon { get; set; }
public int? LastAcceptedPolicyId { get; set; }
}
}
MinimalUserService.cs
namespace Project.Services
{
[Authenticate]
[RequiredRole(new string[] { RoleNames.Admin })]
public class MinimalUserService : Service
{
IUserAuthRepository authRepo = AppHost.Resolve<IUserAuthRepository>() as OrmLiteAuthRepository;
/// <summary>
/// Return a minimalist structure of user insensitive information.
/// </summary>
/// <param name="request">The request containing the ID of the user.</param>
/// <returns>A minimalist structure of user insensitive information.</returns>
public object Get(MinimalUser request)
{
if (request.Identity != null)
return new MinimalUser(authRepo.GetUserAuth(request.Identity.ToString()));
else if (request.Username != null)
return new MinimalUser(authRepo.GetUserAuthByUserName(request.Username));
else
return null;
}
}
}
From my test project, I run the following test:
[TestMethod]
public void GetMinimalUserByUsername()
{
AuthResponse authResponse = client.Post<AuthResponse>("/auth", new Auth
{
UserName = "accountwithadminrole",
Password = "blablabla",
RememberMe = true,
provider = CredentialsAuthProvider.Name
});
MinimalUser request = new MinimalUser
{
DisplayName = BaseAccounts.System,
};
MinimalUser user = client.Get<MinimalUser>(request);
Assert.IsNotNull(user);
}
I clearly see, before issuing the client.Get method, that the request object have all its properties set to null except for the DisplayName which has the value "system". When this request is received by the MinimalUserService Get method, the value "system" is now assigned to the property UserName and DisplayName is null.
Also, I've tried to comment properties one by one in the MinimalUser class, suspecting one of its field could be causing serialization problem and I would end up having random 'Bad Request' when commenting a certain number of properties. Although, I could comment a properties randomly and one property that previously caused a 'Bad Request' would not do it depending on others properties commented out.
I'm really confused about how this can possibly happens. I feel the service and DTO are simple compared to others from this same project but I'm sure I'm doing something really stupid here.
Don't hesitate to ask for more details, it will be my pleasure to give all information you need.
Thank you.
The reason for Username to be populated instead of DisplayName is because of the routes you have defined for MinimalUser. In MinimalUser.cs you defined 2 identical routes:
[Route("/User/{Identity}", "GET")]
[Route("/User/{Username}", "GET")]
[Route("/User/{DisplayName}", "GET")]
Username and Displayname are both strings. This makes it impossible for ServiceStack to determine the appropriate route direct the request to as it cannot differentiate between the routes. You can fix this by either removing a route, or by adding additional text to one of the routes; eg /User/ByDisplayName/{Username}.

Unexpected results returning a custom AuthenticateResponse in the new version of ServiceStack

I'm having an issue returning a custom AutenticateResponse in the new version of ServiceStack. This code worked in the previous version of ServiceStack, but after the upgrade it is no longer functioning as expected.
The AuthenticateResponse
public class CustomAuthResponse : AuthenticateResponse
{
public List<CustomCompanyDTO> Companies { get; set; }
public List<string> Roles { get; set; }
public List<string> Permissions { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
}
The Service
public class CurrentUserService : AppServiceBase
{
public object Any(CurrentUser cu)
{
CustomAuthResponse response = new CustomAuthResponse();
response.DisplayName = UserSession.DisplayName;
response.Email = UserSession.Email;
response.Companies = UserSession.Companies;
response.UserName = UserSession.UserName;
response.Roles = UserSession.Roles;
response.Permissions = UserSession.Permissions;
return response;
}
}
In v3 I can call the CurrentUserService and it returns all the data as expected. In v4 when I call CurrentUserService none of the custom fields are included in the response.
I can work around this particular call by changing the code as follows:
public class CurrentUserService : AppServiceBase
{
public object Any(CurrentUser cu)
{
CustomAuthResponse response = new CustomAuthResponse();
var x = new
{
DisplayName = UserSession.DisplayName,
Email = UserSession.Email,
Companies = UserSession.Companies,
UserName = UserSession.UserName,
Roles = UserSession.Roles,
Permissions = UserSession.Permissions,
};
return x;
}
}
The above code works as expected. I can certainly change my code to work this way, I'm mostly wondering what has changed as I'm curious if it will impact my code in other places. I'm seeing the same issue when trying to return ny CustomAuthResponse from the Authenticate call my custom CredentialsAuthProvider.
The issue is likely that DataContract attributes are now inherited and if a DTO is marked as a [DataContract] it's opt-in and only the properties marked with DataMember are serialized.
As AuthenticateResponse is a DataContract, if you want to re-use the DTO you should mark the properties you want serialized with a [DataMember] attribute, e.g:
[DataContract]
public class CustomAuthResponse : AuthenticateResponse
{
[DataMember]
public List<CustomCompanyDTO> Companies { get; set; }
[DataMember]
public List<string> Roles { get; set; }
[DataMember]
public List<string> Permissions { get; set; }
[DataMember]
public string DisplayName { get; set; }
[DataMember]
public string Email { get; set; }
}

JsonConvert.DeserializeObject<T>(JsonString) returning all Properties<T> as Null

I am having trouble in converting a JSON string to a C# object. Very basic but not getting the desired output. What I am doing wrong?
Here is my string (as provided by Google authorization server)
{
"access_token" : "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "yyyyyyyyyyyyyyyyyyyyyyy"
}
Here is the class:
public class GoogleAuthProperty
{
public string AccessToken { get; set; }
public string TokenType { get; set; }
public long ExpiredIn { get; set; }
public string RefreshToken { get; set; }
}
I am doing this:
var prop = JsonConvert.DeserializeObject<GoogleAuthProperty>(responseFromServer);
but not getting any values in the property list of prop
prop.AccessToken is null;
prop.ToeknType is null;
prop.ExpiredIn is 0;
prop.RefreshToken is null;
Reference:
Newtonsoft.Json
Version: 4.5.0.0
The property names in your JSON do not match the property names in your class (because of the underscores), so you are getting default values. You can fix this by decorating the properties in your class with the JsonProperty attribute and specifying the property name used in the JSON.
Use this class for deserialization
public class SampleResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}

Resources