Json Deserialization BodyStyle Wrap issue using IPWorks nSoftware - servicestack

I am using IPWorks nsoftware for creating service. In it, to call a service I am using
Rest rest = new Rest();
rest.Accept = "application/json";
rest.ContentType = "application/json";
rest.User = "UserName";
rest.Password = "Password";
rest.Get(#"http://Foo.com/roles.json");
string result = rest.TransferredData;
var listRoles = JsonSerializer.DeserializeFromString<List<role>>(result);
I am getting the Json response as a string
[{"role":{"name":"Administrator","created_at":"2012-02-11T09:53:54-02:00","updated_at":"2012-04-29T23:43:47-04:00","id":1"}},{"role":{"name":"NormalUser","created_at":"2013-02-11T08:53:54-02:00","updated_at":"2013-04-29T23:43:47-03:00","id":2"}}]
Here the json string contains my domain object “role” which gets appended to my response (i.e the body style of the message is wrapped) .
I am using ServiceStack.Text’s Deserializer to convert the response string to my object. But since it’s wrapped, the deserilization is incorrect.
Is there anything that I am missing here ? Is there any “BodyStyle” attribute which could be added to the Rest request?

The GitHubRestTests shows some of the different ways you can deserialize a 3rd party json API with ServiceStack's JSON Serializer.
If you want to deserialize it into typed POCOs then judging by your JSON payload the typed POCOs should look something like:
public class RolePermissionWrapper
{
public Role Role { get; set; }
public Permission Permission { get; set; }
}
public class Role
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime? Created_At { get; set; }
public DateTime? Updated_At { get; set; }
}
var listRoles = JsonSerializer.DeserializeFromString<List<RolePermissionWrapper>>(result);

Related

Why is service stack returning a Int64 instead of Int32?

My model SecPermission has the column Id = int which is Int32. When I add a new record why is it returning the newly added ID as Int64?
Service method
public object Post(AddPermission request)
{
var perm = request.ConvertTo<SecPermission>();
perm.AuditUserId = UserAuth.Id;
LogInfo(typeof(SecPermission), request, LogAction.Insert);
return Db.Insert(perm);
}
Unit Test code
using (var service = HostContext.ResolveService<SecurityService>(authenticatedRequest))
{
///**this line is returning an object with Int64 in it.
int id = (int) service.Post(new AddPermission { Name = name, Description = "TestDesc" });
service.Put(new UpdatePermission { Id = permission, Name = name,Description = "TestDesc" });
service.Delete(new DeletePermission { Id = Convert.ToInt32(id)});
}
public class SecPermission : IAudit
{
[AutoIncrement]
[PrimaryKey]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(75)]
public string Description { get; set; }
[Required]
public PermissionType PermissionType { get; set; }
public int AuditUserId { get; set; }
public DateTime AuditDate { get; set; } = DateTime.Now;
}
You should never return a Value Type in a ServiceStack Service, it needs to be a reference Type, typically a Typed Response DTO but can also be a raw data type like string or byte[] but it should never be a Value Type like an integer which will fail to work in some ServiceStack features.
For this Service I'd either return the SecPermission object or a AddPermissionResponse object with the integer in the result value.
Please note that OrmLite Insert() API returns a long which is why you're seeing a long, however you need to either call Save() or specify selectIdentity:true in order to fetch the newly inserted id of an [AutoIncrement] primary key, e.g:
var newId = db.Insert(perm, selectIdentity:true);
or
Db.Save(perm);
var newId = perm.Id; //auto populated with auto incremented primary key
Also you don't need both [PrimaryKey] and [AutoIncrement] in OrmLite as [AutoIncrement] specifies a Primary Key on its own as does using an Id property convention.
Also if you're going to call the Service directly you may as well Type the Response to avoid casting, e.g:
public SecPermission Post(AddPermission request)
{
//...
Db.Save(perm);
return perm;
}
Then you don't need to cast when calling it directly, e.g:
var id = service.Post(new AddPermission { ... }).Id;
There's no behavioral difference in ServiceStack for using object or a typed response like SecPermission although it's preferably to specify it on your Request DTO using the IReturn<T> interface marker, e.g:
public AddPermission : IReturn<SecPermission> { ... }
As it enables end-to-end Typed APIs when called from Service Clients, e.g:
SecPermission response = client.Post(new AddPermission { ... });

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 AutoQuery not working for DateTime values

I have a ServiceStack service using autoquery where the DateTime greater than or less than are being ignored.
Here is my request DTO:
public class GetSources : QueryBase<DbSource, Source>
{
public string Name { get; set; }
public string NameContains { get; set; }
public string NameStartsWith { get; set; }
public DateTime? LastUpdatedDateGreaterThan { get; set; }
public DateTime? LastUpdatedDateLessThan { get; set; }
}
The database table poco generated from the ormlite T4 template looks like this:
[Alias("DbSources")]
[Schema("SomeSchema")]
public partial class DbSource
{
[AutoIncrement]
public int Id { get; set;}
[Required]
public string Name { get; set;}
[Required]
public DateTime LastUpdatedDate { get; set;}
}
In the service I do some validation and then use AutoQuery like this:
var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams());
q.Join<DbSource, CompanySource>((source, companySource) => source.Id == companySource.SourceId && companySource.CompanyID == companyId);
return AutoQuery.Execute(dto, q);
I'm using mstest
[TestMethod]
public void GetSources_LastUpdatedGreaterThan()
{
var expected = DateTime.Now;
var query = new GetSources { LastUpdatedDateGreaterThan = expected};
QueryResponse<Source> result;
using (var service = appHost.Container.Resolve<SourceService>())
{
service.Request = new MockHttpRequest();
result = service.Any(query);
}
log.Info(result.ToJson());
result.Results.ForEach(src => Assert.IsTrue(src.LastUpdatedDate > expected));
}
Name, NameContains, and NameStartsWith all work as expected in other tests, but both LastUpdatedDateGreaterThan and LastUpdatedDateLessThan do not generate a where clause. In my AutoQuery setup all of the properties are defaults except for EnableUntypedQueries which is false.
I know I can explicitly add the where for them in the service. i.e.
q.Where(source => source.LastUpdatedDate > dto.LastUpdatedDateGreaterThan);
But if possible I would like AutoQuery to take care of it. Does DateTime work with AutoQuery? Or am I doing something wrong in my code.
I ran through the Servicestack AutoQuery unit tests that mythz created using sql server. I tested using a database view which my original project was querying against and I wasn't able to replicate the issue I'm having. For now I'm going to just add the QueryField attribute to the DateTime properties on the Query model like this:
[QueryField(Template = "{Field} > {Value}", Field = "LastUpdatedDate")]
public DateTime? LastUpdatedDateGreaterThan { get; set; }
Adding the attribute gives me what I need. I'll spend some time tracking down the culprit in my code later.

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

servicestack serializes to empty json string

I am having a strange issue with ServiceStack (SS). The entity I pass to the method is always serialized to empty json string by SS. So s is always "{}". I debug and see that the entity is a hydrated instance with properties with values.
Any ideas why this is the case?
public virtual void Serialize<TEntity>(TEntity entity, Stream stream)
{
// s is always {}
var s = JsonSerializer.SerializeToString(entity);
// rest is not important at this point...
s = JsvFormatter.Format(s);
using (var writer = new StreamWriter(stream))
{
writer.Write(s);
}
}
I am editing the question show exactly what the passed in (VolumeCreated) entity is.
public class VolumeEvent : IEvent<VolumeID>
{
public VolumeEvent(VolumeID identity)
{
Identity = identity;
}
#region Implementation of IEvent<out VolumeIdentity>
public VolumeID Identity { get; private set; }
#endregion
}
public class VolumeCreated : VolumeEvent
{
public DateTime PublishDate { get; set; }
public string Title { get; set; }
public VolumeCreated(VolumeID identity, string title, DateTime publishDate)
: base(identity)
{
Title = title;
PublishDate = publishDate;
}
}
ServiceStack serializes only serializes public properties.

Resources