Service returning string only has added quotes when coming from the cache - caching

I built a simple Hello service that uses the cache. DTO:
[DataContract]
[Route("/cachedhello/{Name}")]
public class CachedHello : IReturn<string>
{
[DataMember]
public string Name { get; set; }
public string CacheKey
{ get { return "urn:cachedhello:nm=" + Name; } }
}
Here is the service:
public class CachedHelloService : Service
{
public ICacheClient CacheClient { get; set; }
public object Any(CachedHello request)
{
return base.Request.ToOptimizedResultUsingCache(
this.CacheClient, request.CacheKey, CacheExpiryTime.DailyLoad(), () =>
{
return "(Cached) Hello, " + request.Name;
});
}
}
When I use the JSONServiceClient to call this service, the returned string has quotes around it. when I look at the cache entries in my database, it does look like an extra set of quotes have been put around the .json version of the entry:
urn:cachedhello:nm=Matt (Cached) Hello, Matt
urn:cachedhello:nm=Matt.json """(Cached) Hello, Matt"""
urn:cachedhello:nm=Matt.json.deflate U9JwTkzOSE3RVPBIzcnJ11HwTSwpUQIA
Here's the code that calls the service from VB.NET
Dim s = _ServiceClient.Send(Of String)(New CachedHello() With {.Name = "Matt"})

We've removed double-encoding of raw string responses in this commit. This issue should now resolved in the latest v4.0.33+ of ServiceStack that's now available on MyGet.

Related

Entity Framework Core - EF Core 2.2 - 'Point.Boundary' is of an interface type ('IGeometry')

I am trying the new functionality with EF Core 2.2. It is based on the following article. "Announcing Entity Framework Core 2.2"
https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-entity-framework-core-2-2/
I installed the following Nuget package.
I added the following to my model.
using NetTopologySuite.Geometries;
//New as of EF.Core 2.2
//[Required]
//[NotMapped]
public Point Location { get; set; }
During my application startup I get the following error in my Database Context on the following line:
Database.EnsureCreated();
System.InvalidOperationException
HResult=0x80131509
Message=The property 'Point.Boundary' is of an interface type ('IGeometry'). If it is a navigation property manually configure the relationship for this property by casting it to a mapped entity type, otherwise ignore the property using the NotMappedAttribute or 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Source=Microsoft.EntityFrameworkCore
You need to call UseNetTopologySuite(). Example here:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var connectionString = configuration.GetConnectionString("DefaultConnection");
optionsBuilder.UseSqlServer(connectionString, opts => opts.UseNetTopologySuite());
}
public DbSet<Test> Tests { get; set; }
}
public class Test
{
public int Id { get; set; }
public Point Location { get; set; }
}
I ran into this problem because I had a
if (!optionsBuilder.IsConfigured) around everything in my OnConfiguring. I had to remove this in order to get add-migrations to work.
As Kyle pointed out you need to call UseNetTopologySuite(), but I would call it during ConfigureServices like this:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddEntityFrameworkNpgsql()
.AddDbContext<MyDBContext>(opt =>
opt.UseNpgsql(Configuration.GetConnectionString("MyDBConnection"),
o=>o.UseNetTopologySuite()))
.BuildServiceProvider();
...
}
...
}

Serialization attributes on TableEntity in Azure Table Storage

Im using web API to return data in azure table storage. Im returning a class that I 'm inheriting TableEntity in a class and adding properties but want to keep to the .Net convention of capitalized property names but also keep to the JavaScript/json convention of lowercase properties names.
I've tried adding the Json.net property attributes to the class but it appears to be ignored. E.g.:
[JsonProperty("id")]
public string ID {get;set;}
If the instance has a value set on ID, null is represent in the serialized result.
According to your description, I tested this issue on my side and found it works well on my side and Azure. Here is my detailed steps, you could refer to it.
Create a controller named UserInfoController in the Web API application with the Get function like this:
// GET: api/UserInfo
[HttpGet]
public async Task<string> Get()
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(<your-Storage-ConnectionString>);
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable cloudTable = tableClient.GetTableReference("UserInfo");
TableQuery<User> query = new TableQuery<User>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "Grade Four"));
var results =await cloudTable.ExecuteQuerySegmentedAsync(query, null);
//Serialize the object to string by using the latest stable version of Newtonsoft.Json
string jsonString = JsonConvert.SerializeObject(results);
return jsonString;
}
Entity
public class User : TableEntity
{
public User(string partitionKey, string rowKey)
{
this.PartitionKey = partitionKey;
this.RowKey = rowKey;
}
public User() { }
[JsonProperty("id")]
public long ID { get; set; }
[JsonProperty("username")]
public string UserName { get; set; }
[JsonProperty("phone")]
public string Phone { get; set; }
[JsonProperty("age")]
public int Age { get; set; }
}
Result
Deploy the Web API application to Azure, then you could find the following result by calling the function via Fiddler.
In summary, please try to check the version of Json.NET you are using. If you aren't using the latest (9.0.1), then please try to upgrade to the latest version and run your application again to find whether it could work as expected.
FYI - while this doesn't answer the direct answer of how to get TableEntity to respect JSON.net attributes... I was able to solve the use case by overriding the ReadEntity and WriteEntity method in the inherited class:
e.g.
public class User : TableEntity{
//Upper case name
public string Name {get; set};
public override void ReadEntity(IDictionary<string, AzureTableStorage.EntityProperty> properties, OperationContext operationContext){
base.ReadEntity(properties, operationContext);
//lower case
this.Name = properties["name"];
}

Using Automapper to map object to realm object with Xamarin and c#

I am creating an Xamarin.iOS app and a Realm database.I would like to keep my POCO objects separate from my RealmObject so what I did was use a repository pattern and within the repository I tried to use AutoMapper to map the POCO to the RealmObject
e.g. (subset)
public class PlaceRepository : IPlaceRepository
{
private Realm _realm;
public PlaceRepository(RealmConfiguration config)
{
_realm = Realm.GetInstance(config);
}
public void Add(Place place)
{
using (var trans = _realm.BeginWrite())
{
var placeRealm = _realm.CreateObject<PlaceRealm>();
placeRealm = Mapper.Map<Place, PlaceRealm>(place);
trans.Commit();
}
}
So, if I debug my code everything maps OK and placeRealm is populated OK but when I commit nothing gets saved to the Realm db. The following is my RealmObject
public class PlaceRealm : RealmObject
{
[ObjectId]
public string Guid { get; set; }
public string Title { get; set; }
public string Notes { get; set; }
}
and this is my POCO Place
public class Place
{
public string Guid { get; set; }
public string Title { get; set; }
public string Notes { get; set; }
}
And AutoMapper is initialized like so:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Place, PlaceRealm>();
cfg.CreateMap<PlaceRealm, Place>();
});
All standard stuff. Has anyone else managed to get something similar working?
Your poco 'Place' is called 'PlaceRealm'. I suspect that is a typo. (made edit)
I suspect that Automapper is instantiating a new object overwriting your original 'placeRealm' object.
Perhaps you could try
Mapper.Map(place, placeRealm);
in place of your current mapping.
which should just copy the values to your already instatiated and tracked object.
(no need to store the return value).
You might also want to make explicit which properties (3) you are mapping as currently Automapper will map all including those in the base class.
On a side note, you may run into performance issues with Automapper. I found it to be the performance bottleneck in some apps. ExpressMapper is a nice alternative.

The Delta for Patch is null

Here are my Entities. I am using entity framework code first.
public class Trade
{
public Guid Id { get; set; }
[MaxLength(10)]
public string AssetClass { get; set; }
public TradeBatch Batch { get; set; }
}
public class TradeBatch
{
public TradeBatch()
{
StartedOn = DateTime.Now;
}
public Guid Id { get; set; }
public DateTime StartedOn { get; set; }
public List<Trade> Trades { get; set; }
}
In My Controller I have:
[AcceptVerbs("PATCH")]
public void UpdateTrade(Guid id, Delta<Trade> update)
{
var tradeToUpdate = _repTradeService.GetRepTradeById(id);
update.Patch(tradeToUpdate);
_repTradeService.SaveChanges();
}
When I Make a request (using fiddler), update is null.
Here is the patch Request:
PATCH http://localhost:61579/api/RepTrades/4e43b48a-a4fd-4ffc-841d-08dac55deb60 HTTP/1.0
User-Agent: Fiddler
Host: localhost:61579
Content-Length: 55
Content-Type: application/json
{"AssetClass":"Test"}
The value for "Update" in the Patch Action is always null. Any pointers to why?
You may want to try setting the content-type header to application/json;odata=verbose
I would have just commented but don't have the reputation yet.
Your JSON is fine, and the method should accept it as far as I can see. You can see what the exact error is by adding the following line of code at the top of your PATCH method:
if (!ModelState.IsValid) {
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
}
This way, if your JSON is not valid according to the model the method is expecting, it returns a HTTP 400 Bad Request message, along with the ModelState. The message of that response will contain the reason why the ModelState is not valid.
In my case the answer from #kazu helped me find the problem because it gave me a break point where the debugger could reveal the problem.
I had a setter in my class, which was trying to set a property on an object which had not been initialised. By breaking with the debugger on the "throw" command, I was able to see the stack trace in the properties of the ModelState object, and the stacktrace said my setter on a particular field was throwing "Object Reference Not Set". With that I could immediately see the problem.
My object was like this:
public MyObject
{
private PrivateObjectType _privateObject;
public MyObject()
{
}
public string myProperty
{
get { return _privateObject.myProperty; }
set { _privateObject.myProperty = value; }
}
}
So obviously I needed to put this in the constructor:
_privateObject = new PrivateObjectType();

Visual Studio WCF Client creates classes with missing properties, adds ExtensionData property instead

I have a WCFService that returns sundry types of Data in this kind of a way:
[DataContract( Name="Amazing", NameSpace="http://schemas.myorganisation.com/DataContract1")]
Public class AmazingDto
{
[DataMember( Order=0, IsRequired=true )]
public string Name { get; set; }
[DataMember( Order=0, IsRequired=true )]
public bool IsAmazing { get; set; }
}
And then
[DataContract ( Name="GetAmazingListResponse", NameSpace="http://schemas.myorganisation.com/DataContract1")]
Public class GetAmazingListResponseDto
{
[DataMember(Order=0, IsRequired-true, EmitDefaultValue=False)]
public ICollection<AmazingDto> AmazingList{ get; set; }
}
Also
[DataContract(Name = "Response", Namespace = "http://schemas.myorganisation.com/DataContract1")]
public class ResponseDto<TData> : BaseResponseDto
{
public ResponseDto();
[DataMember(Order = 0, IsRequired = true)]
public StatusDto Status { get; set; }
[DataMember(Order = 1, IsRequired = false, EmitDefaultValue = false)]
public TData Data { get; set; }
}
And then
public ResponseDto<GetAmazingListResponseDto> GetAmazingList()
{
var response = new ResponseDto<GetAmazingListDto>
{
Status = new StatusDto { StatusResult = StatusResultEnum.Success },
Data = new GetAmazingListResponseDto
{
AmazingList = new List<AmazingDto>
{
new AmazingDto { Name="Ponies", IsAmazing=true },
new AmazingDto { Name="Glenatron", IsAmazing=false }
}
}
};
return response;
}
Now when I make a call to that service using a tool like SoapUI I get exactly the response I might expect.
<GetAmazingListResult xmlns:a="http://schemas.myorganisation.com/DataContract1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Status>
<a:StatusResult>Success</a:StatusResult>
</a:Status>
<a:Data xmlns:b="http://schemas.myorganisation.com/DataContract1">
<b:AmazingList>
<b:Amazing>
<b:Name>Ponies</b:Name>
<b:IsAmazing>true</b:IsAmazing>
</b:Amazing>
<b:Amazing>
<b:Name>Glenatron</b:Name>
<b:IsAmazing>false</b:IsAmazing>
</b:Amazing>
</b:AmazingList>
</a:Data>
</GetAmazingListResult>
However, when I use Visual Studio 2010 to create a Service Reference and make a call like this:
var client= new FindoutAmazingnessServiceClient();
var response = client.GetAmazingList();
What I find is that response only has two properties, Status and ExtensionData. I have seen this described in other SE questions but the answer was always that something was missing a DataContract or DataMember on the data contracts. I definitely have those, so something else must be happening so that VS.Net can't see my classes. I have tried referencing the DTO library that contains these files and trying to configure the reference to match types with that library, but it makes no difference.
Where am I going wrong?
Just Add [DataMember] to your data members. It solved my problem.
The solution I have found is, as I am working against my own WCF service, to import the interfaces into my client and then use ChannelFactory to set up the connection. This works very well in my scenario, but doesn't solve the problem I am raising with this question.

Resources