How does Protobuf-net support for Dictionary/KeyValuePair works? - protocol-buffers

I am trying to understand protobuf-net's Dictionary/KeyValuePair support. We would like to use the underlying binary stream and the generated proto file from java, but the generated .proto file contains what look like a custom type called Pair_String_Int32.
Can someone please shed some light on this?
I've got a class mapped like this:
[DataContract]
public class ForwardCurve
{
[DataMember(Order=1, IsRequired = true)]
public string Commodity { get; set; }
[DataMember(Order = 2, IsRequired = false)]
public IDictionary<string, int> DictValue { get; set; }
[DataMember(Order = 3, IsRequired = false)]
public IList<string> ListValue { get; set; }
}
The generated .proto file using Serializer.GetProto will be:
message ForwardCurve {
required string Commodity = 1;
repeated Pair_String_Int32 DictValue = 2;
repeated string ListValue = 3;
}
So what is Pair_String_Int32 (and what is going into the protobuffer byte stream) and is there any way of mapping this so that protobuf, by using protoc can create the equivalent mapping code in Java?

To get this for work add a new message to the generated .proto file that looks like this.
message Pair_String_Int32 {
required string Key = 1;
required int32 Value = 2;
}
Then protoc will be able to create the corresponding code for Java.

I can check later (I'm on iPod at the moment) but I believe is it simply a "repeated" set of a dummy type with members key=1 value=2 (using the default types for each - so c# string maps to proto string etc). I am in the process of re-implementing GetProto for v2, so I'll try to ensure these dummy types are included in the output.

Related

Web API method with FromUri attribute is not working in Postman

I have written the below simple Web API method.
[HttpGet]
[HttpPost]
public int SumNumbers([FromUri]Numbers calc, [FromUri]Operation op)
{
int result = op.Add ? calc.First + calc.Second : calc.First - calc.Second;
return op.Double ? result * 2 : result;
}
Below is the model class for Numbers:
public class Numbers
{
public int First { get; set; }
public int Second { get; set; }
}
Below is the model class for Operation:
public class Operation
{
public bool Add { get; set; }
public bool Double { get; set; }
}
Below is how I am trying to test in Postman. But, as you can see I am getting "0" as output. When debugged the code, understood that values are not passing from Postman into code.
One another user also posted the same problem here. But, whatever the resolution he showed, I am doing already, but I am not getting answer.
Can anyone please suggest where I am doing wrong?
There are 2 major issues with your post, firstly your controller (due to [FromUri]
binding) is specifying that the arguments need to be passed as Query String parameters and not Http Header values.
The second issue is that you have defined two complex type parameters that you want to obtain the values form the URI, this is not supported.
How to pass in Uri complex objects without using custom ModelBinders or any serialization?
This is a great writeup on how to fully exploit the [FromUriAttribute][2] up to ASP.Net Core 2.2, many of the principals apply to the FromQueryAttribute which is still used the current in ASP.Net 6.
We can use [FromUri] to bind multiple primitive typed parameters, or we can bind 1 single complex typed parameter. You cannot combine the two concepts, the reason for this is that when a complex type is used ALL of the query string arguments are bound to that single complex type.
So your options are to create a new complex type that combines all the properties from both types, or declare all the properties of both types as primitive parameters to the method:
http://localhost:29844/api/bindings/SumNumbers1?First=3&Second=2&Add=True&Double=False
http://localhost:29844/api/bindings/SumNumbers2?First=3&Second=2&Add=True&Double=False
[HttpGet]
[HttpPost]
public int SumNumbers1([FromUri] int First, [FromUri] int Second, [FromUri] bool Add, [FromUri] bool Double)
{
int result = Add ? First + Second : First - Second;
return Double ? result * 2 : result;
}
[HttpGet]
[HttpPost]
public int SumNumbers2([FromUri] SumRequest req)
{
int result = req.Add ? req.First + req.Second : req.First - req.Second;
return req.Double ? result * 2 : result;
}
public class SumRequest
{
public int First { get; set; }
public int Second { get; set; }
public bool Add { get; set; }
public bool Double { get; set; }
}
It is also technically possible to use a nested structure, where you wrap the multiple complex with a single outer complex type. Depending on your implementation and host constraints you may need additional configuration to support using . in the query parameters, but a nested or wrapped request implementation would look like this:
http://localhost:29844/api/bindings/SumNumbers3?Calc.First=3&Calc.Second=2&Op.Add=True&Op.Double=False
[HttpGet]
[HttpPost]
public int SumNumbers3([FromUri] WrappedRequest req)
{
int result = req.Op.Add ? req.Calc.First + req.Calc.Second : req.Calc.First - req.Calc.Second;
return req.Op.Double ? result * 2 : result;
}
public class WrappedRequest
{
public Numbers Calc { get; set; }
public Operation Op { get; set; }
}
It is also possible to use a combination of Http Headers and query string parameters, however these are generally harder (less common) to manage from a client perspective.
It is more common with complex parameter scenarios (not to mention more REST compliant) to force the caller to use POST to access your calculation endpoint, then multiple complex types are simpler to support from both a client and API perspective.
If you want to receive parameters using FromUri, shouldn't you pass them in the URL when doing the GET call? A simpler call would be something like this:
[HttpGet]
[Route("{first:int}/{second:int}")]
public int SumNumbers([FromUri]int first, [FromUri]int second)
{
return first+second;
}
And in Postman your call should be more like this (the url)
http://localhost:29844/api/bindings/SumNumbers/5/7
and this would return 12!
Now if you want to pass First and Second as headers and not in the url then you don't want to use FromUri and then your code would change a little bit (you will then need to read the request and dissect it to get every header alone. Something like this:
HttpRequestMessage request = Request ?? new HttpRequestMessage();
string first = request.Headers.GetValues("First").FirstOrDefault();
string second = request.Headers.GetValues("Second").FirstOrDefault();

Expression.Property(param, field) is "trolling" me [System.ArgumentException] = {"Instance property 'B.Name' is not defined for type A"}

Once again, I am facing an issue, this time with LINQ Expression builder and this time I am even struggling to find the reason why it's not working. I have a Database-First EF project with quite a few tables. For this specific case, I have to use 2 of them - DocHead and Contragent. MyService.metadata.cs looks like this:
[MetadataTypeAttribute(typeof(DocHead.DocHeadMetadata))]
public partial class DocHead
{
// This class allows you to attach custom attributes to properties
// of the DocHead class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class DocHeadMetadata
{
// Metadata classes are not meant to be instantiated.
private DocHeadMetadata()
{
}
public string doc_Code { get; set; }
public string doc_Name { get; set; }
public string doc_ContrCode { get; set; }
//...
[Include]
public Contragent Contragent { get; set; }
}
}
[MetadataTypeAttribute(typeof(Contragent.ContragentMetadata))]
public partial class Contragent
{
// This class allows you to attach custom attributes to properties
// of the Contragent class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class ContragentMetadata
{
// Metadata classes are not meant to be instantiated.
private ContragentMetadata()
{
}
public string Code { get; set; }
public string Name { get; set; }
//...
I take some docHeads like this:
IQueryable<DocHead> docHeads = new MyEntities().DocHead;
Then I try to sort them like this:
docHeads = docHeads.OrderByDescending(x => x.Contragent.Name);
It is all working like I want it. I get those docHeads sorted by the name of the joined Contragent. My problem is that I will have to sort them by a field, given as a string parameter. I need to be able to write something like this:
string field = "Contragent.Name";
string linq = "docHeads = docHeads.OrderByDescending(x => x." + field + ")";
IQueryable<DocHead> result = TheBestLinqLibraryInTheWorld.PrepareLinqQueryable(linq);
Unfortunately, TheBestLinqLibraryInTheWorld does not exist (for now). So, I have set up a method as a workaround.
public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
{
var param = Expression.Parameter(typeof(T), "x");
var prop = Expression.Property(param, SortField); // normally returns x.sortField
var exp = Expression.Lambda(prop, param); // normally returns x => x.sortField
string method = Ascending ? "OrderBy" : "OrderByDescending";
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp); // normally returns sth similar to q.OrderBy(x => x.sortField)
return q.Provider.CreateQuery<T>(mce);
}
Normally... yes, when it comes to own properties of the class DocHead - those prefixed with doc_. The disaster strikes when I call this method like this:
docHeads = docHeads.OrderByField<DocHead>("Contragent.Name", true); // true - let it be Ascending order
To be more specific, the exception in the title is thrown on line 2 of the method OrderByField():
var prop = Expression.Property(param, SortField);
In My.edmx (the model), the tables DocHead and Contragent have got a relation already set up for me, which is the following: 0..1 to *.
Once again, I have no problem writing "static" queries at all. I have no problem creating "dynamic" ones via the method OrderByField(), but only when it comes to properties of the class DocHead. When I try to order by a prop of the joined Contragent class - the disaster strikes. Any help will be greatly appretiated, thank you!
The problem is that Expression.Property method does not support nested properties. It does exactly what it says - creates expression that represents a property denoted by propertyName parameter of the object denoted by the expression parameter.
Luckily it can easily be extended. You can use the following simple Split / Aggregate trick anytime you need to create a nested property access expression:
var prop = SortField.Split('.').Aggregate((Expression)param, Expression.Property);

Combining Linq Expressions for Dto Selector

We have a lot of Dto classes in our project and on various occasions SELECT them using Expressions from the entity framework context. This has the benefit, that EF can parse our request, and build a nice SQL statement out of it.
Unfortunatly, this has led to very big Expressions, because we have no way of combining them.
So if you have a class DtoA with 3 properties, and one of them is of class DtoB with 5 properties, and again one of those is of class DtoC with 10 properties, you would have to write one big selector.
public static Expression<Func<ClassA, DtoA>> ToDto =
from => new DtoA
{
Id = from.Id,
Name = from.Name,
Size = from.Size,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
Also, they cannot be reused. When you have DtoD, which also has a propertiy of class DtoB, you would have to paste in the desired code of DtoB and DtoC again.
public static Expression<Func<ClassD, DtoD>> ToDto =
from => new DtoD
{
Id = from.Id,
Length = from.Length,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
So this will escalate pretty fast. Please note that the mentioned code is just an example, but you get the idea.
I would like to define an expression for each class and then combine them as required, as well as EF still be able to parse it and generate the SQL statement so to not lose the performance improvement.
How can i achieve this?
Have you thought about using Automapper ? You can define your Dtos and create a mapping between the original entity and the Dto and/or vice versa, and using the projection, you don't need any select statements as Automapper will do it for you automatically and it will project only the dto's properties into SQL query.
for example, if you have a Person table with the following structure:
public class Person
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
public string Initial { get; set; }
public string PreferredName { get; set; }
public string FormerTitle { get; set; }
public string FormerFamilyName { get; set; }
public string FormerGivenName { get; set; }
}
and your dto was like this :
public class PersonDto
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
}
You can create a mapping between Person and PersonDto like this
Mapper.CreateMap<Person, PersonDto>()
and when you query the database using Entity Framework (for example), you can use something like this to get PersonDto columns only:
ctx.People.Where(p=> p.FamilyName.Contains("John"))
.Project()
.To<PersonDto>()
.ToList();
which will return a list of PersonDtos that has a family name contains "John", and if you run a sql profiler for example you will see that only the PersonDto columns were selected.
Automapper also supports hierachy, if your Person for example has an Address linked to it that you want to return AddressDto for it.
I think it worth to have a look and check it, it cleans a lot of the mess that manual mapping requires.
I thought about it a little, and I didn't come up with any "awesome" solution.
Essentially you have two general choices here,
Use placeholder and rewrite expression tree entirely.
Something like this,
public static Expression<Func<ClassA, DtoA>> DtoExpression{
get{
Expression<Func<ClassA, DtoA>> dtoExpression = classA => new DtoA(){
BDto = Magic.Swap(ClassB.DtoExpression),
};
// todo; here you have access to dtoExpression,
// you need to use expression transformers
// in order to find & replace the Magic.Swap(..) call with the
// actual Expression code(NewExpression),
// Rewriting the expression tree is no easy task,
// but EF will be able to understand it this way.
// the code will be quite tricky, but can be solved
// within ~50-100 lines of code, I expect.
// For that, see ExpressionVisitor.
// As ExpressionVisitor detects the usage of Magic.Swap,
// it has to check the actual expression(ClassB.DtoExpression),
// and rebuild it as MemberInitExpression & NewExpression,
// and the bindings have to be mapped to correct places.
return Magic.Rebuild(dtoExpression);
}
The other way is to start using only Expression class(ditching the LINQ). This way you can write the queries from zero, and reusability will be nice, however, things get harder & you lose type safety. Microsoft has nice reference about dynamic expressions. If you structure everything that way, you can reuse a lot of the functionality. Eg, you define NewExpression and then you can later reuse it, if needed.
The third way is to basically use lambda syntax: .Where, .Select etc.. This gives you definitely better "reusability" rate. It doesn't solve your problem 100%, but it can help you to compose queries a bit better. For example: from.MyCList.Select(dtoCSelector)

Classes created in F# serialized incorrectly in a C# WebApi/MVC project

I created a class in FSharp like so:
type Account() = class
let mutable amount = 0m
let mutable number = 0
let mutable holder = ""
member this.Number
with get () = number
and set (value) = number <- value
member this.Holder
with get () = holder
and set (value) = holder <- value
member this.Amount
with get () = amount
and set (value) = amount <- value
end
When I reference the project from my C# WebAPI/MVC application like this
[HttpGet]
public Account Index()
{
var account = new Account();
account.Amount = 100;
account.Holder = "Homer";
account.Number = 1;
return account;
}
I am getting the following results. Note that the field name are camelCased.
<Account xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ChickenSoftware.MVCSerializationIssue">
<amount>100</amount>
<holder>Homer</holder>
<number>1</number>
</Account>
When I create a similar class in C# like this
public class NewAccount
{
public int Number { get; set; }
public String Holder { get; set; }
public int Amount { get; set; }
}
the output is Pascal cased
<NewAccount xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ChickenSoftware.MVCSerializationIssue.Api.Models">
<Amount>100</Amount>
<Holder>Homer</Holder>
<Number>1</Number>
</NewAccount>
I first thought it was the Json Serializer (Newtonsoft by default I think), but when I put a break in the controller, I see that the C# class only has its public properties exposed and that the F# class has both the Property and the backing field exposed. I tried to add a "private" keyword to the F# let statements but I got this:
Error 1 Multiple visibility attributes have been specified for this identifier. 'let' bindings in classes are always private, as are any 'let' bindings inside expressions.
So is there a way that the F# classes can treated the same as C# from Web Api?
See Mark's blog on this very issue: http://blog.ploeh.dk/2013/10/15/easy-aspnet-web-api-dtos-with-f-climutable-records/

Do i need to create automapper createmap both ways?

This might be a stupid question! (n00b to AutoMapper and time-short!)
I want to use AutoMapper to map from EF4 entities to ViewModel classes.
1) If I call
CreateMap<ModelClass, ViewModelClass>()
then do I also need to call
CreateMap<ViewModelClass, ModelClass>()
to perform the reverse?
2) If two classes have the same property names, then do I need a CreateMap statement at all, or is this just for "specific/custom" mappings?
For the info of the people who stumble upon this question. There appears to be now a built-in way to achieve a reverse mapping by adding a .ReverseMap() call at the end of your CreateMap() configuration chain.
In AutoMapper you have a Source type and a Destination type. So you will be able to map between this Source type and Destination type only if you have a corresponding CreateMap. So to answer your questions:
You don't need to define the reverse mapping. You have to do it only if you intend to map back.
Yes, you need to call CreateMap to indicate that those types are mappable otherwise an exception will be thrown when you call Map<TSource, TDest> telling you that a mapping doesn't exist between the source and destination type.
I've used an extension method do mapping both ways
public static IMappingExpression<TDestination, TSource> BothWays<TSource, TDestination>
(this IMappingExpression<TSource, TDestination> mappingExpression)
{
return Mapper.CreateMap<TDestination, TSource>();
}
usage:
CreateMap<Source, Dest>().BothWays();
Yes, or you can call CreateMap<ModelClass, ViewModelClass>().ReverseMap().
If two classes have same Member(Property,Field,GetMethod()), you needn't call CreateMap<TSrc,TDest>. Actually, if every member in TDest are all exist in TSrc, you needn't call CreateMap<TSrc,TDest>. The following code works.
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
class Person2
{
public string Name { get; set; }
public int? Age { get; set; }
public DateTime BirthTime { get; set; }
}
public class NormalProfile : Profile
{
public NormalProfile()
{
//CreateMap<Person2, Person>();//
}
}
var cfg = new MapperConfiguration(c =>
{
c.AddProfile<NormalProfile>();
});
//cfg.AssertConfigurationIsValid();
var mapper = cfg.CreateMapper();
var s3 = mapper.Map<Person>(new Person2 { Name = "Person2" });

Resources