I use the following command to generate a proxy class for a WCF service :
svcutil.exe" /out:C:\SomePath\.... /n:*,Internal.FooNameSpace
http://localhost/MyService.svc
The following class :
[ProtoContract]
[ServiceContract]
public class Foo
{
[ProtoMember(1)]
[DataMember(Order = 0)]
public string Bar { get; set; }
}
Becomes :
public partial class Foo : object, System.Runtime.Serialization.IExtensibleDataObject
{
private string BarField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Bar
{
get
{
return this.BarField;
}
set
{
this.BarField = value;
}
}
}
Is there a way to keep some specific attributes on the generated class ? (eg : ProtoMember in this case). I could off course hack the proxy but it create maintenance problems.
If you're adding that as a service reference, then nope: there's no way to retain that information - it simply isn't in the WCF endpoint.
IIRC, though, the WCF code-gen does actually come up with incremental Order values when you have multiple properties - i.e. the next property would be [System.Runtime.Serialization.DataMemberAttribute(Order = 1)], then 2 etc. So one option is to in a different file (the beauty of partial class), define (in the same namespace, etc) additional info about your type:
[ProtoContract(DataMemberOffset = 1)]
public partial class Foo { }
What this means is: when processing [DataMember], add 1 to every value - that means that you should get the required 1,2,3,4... and everything will be fine, and you haven't had to change the code.
Alternatively, you can be explicit:
[ProtoContract]
[ProtoPartialMember(1, nameof(Foo.Bar))]
[ProtoPartialMember(2, nameof(Foo.AnotherProp))]
public partial class Foo { }
This gives you a lot more flexibility to specify nuance about the properties.
As another alterative, you can configure everything at runtime:
RuntimeTypeModel.Default.Add(typeof(Foo), false)
.Add(1, nameof(Foo.Bar))
.Add(2, nameof(Foo.AnotherProp));
// or AddField to get the ValueMember that you can use to set
// fine-grained control
Finally, you can just ship the data contract dll, and tell svctil to use the types it already contains. You do this with the /reference:<file path> command-line switch, or there's a similar feature when using the UI tools (that lets you choose from the available dlls).
As a second "finally" (because one is not enough): you could describe the data instead as a .proto schema, and just tell the recipient to do the codegen locally and tell svcutil to exclude it (/excludeType: or /reference:). Note that the in progress rewrite of "protogen" does not currently include [DataContract]/[DataMember] attributes, but I could get that added today if it would be useful.
Related
We have a POST action in our asp.net core application that accepts a dynamic object.
[HttpPost]
public Task<ActionResult> SubmitAsync(dynamic unitOfWork)
We'd like to transform this POST action to a gRPC server and we'd like to continue receiving dynamic objects in the gRPC service. What is the equivalent of C# dynamic definition in gRPC protobuf file definition? Or if that cannot be achieved what's the best way to receive a dynamic object?
That isn't really a thing right now. In protobuf terms, Any is the closest thing, but I have not yet implemented that in protobuf-net (it is on my short term additions list). The legacy "dynamic types" feature in protobuf-net (that sends type metadata) is actively being phased out, with Any being the preferred route since it allows cross-platform usage and doesn't have the same metadata dependencies.
Frankly, though, I'd probably say "just don't do this"; instead, prefer oneof; it isn't likely that you actually mean "anything" - you probably just mean "one of these things that I expect, but I don't know which", and oneof expresses that intent. More: protobuf-net implements inheritance via oneof, so a good option is something like:
[ProtoContract]
[ProtoInclude(1, typeof(FooRequest))]
[ProtoInclude(2, typeof(BarRequest))]
public abstract class RequestBase {}
[ProtoContract]
public class FooRequest {}
[ProtoContract]
public class BarRequest {}
You can pass messages with fields whose type was not known in advance. You can also pass messages with fields that are not typed, such as dynamic objects that can take any scalar values, and collections null values are allowed.
To do so, import the proto file "google/protobuf/struct.proto" and declare the
dynamic type as google.protobuf.Value.
So, first add bellow line at the top of your proto file:
import "google/protobuf/struct.proto";
Here my sample message with two dynamic fields:
message BranchResponse {
google.protobuf.Value BranchId = 1;
google.protobuf.Value BranchLevel = 2;
}
Note that: the generated type in C# is Value and belongs to the Google.Protobuf.WellKnownTypes namespace, which belongs itself to the Google.Protobuf assembly. This type inherits from the IMessage, IMessage, IEquatable, IDeepCloneable, and IBufferMessage interfaces that all belong to the Google.Protobuf assembly, except for IEquatable, which comes from the .NET System.Runtime assembly. To write and read dynamic values, we have a set of methods available that shown bellow: (these are write static functions)
We can fill BranchResponse model like this:
var branch = new BranchResponse();
branch.BranchId = Value.ForNumber(1);
branch.BranchLevel = Value.ForStruct(new Struct
{
Fields = {
["LevelId"] = Value.ForNumber(1),
["LevelName"] = Value.ForString("Gold"),
["IsProfessional"] = Value.ForBool(true)}
});
The read Value type is straightforward. The Value type has a set of properties that exposes its value in the wanted type. (these are read static functions)
At the end, you need to read data from your response model like this:
Here my c# classes that my response model is supposed to bind to them.
public class BranchModel
{
public int BranchId { get; set; }
public LevelModel Level { get; set; }
}
public class LevelModel
{
public int LevelId{ get; set; }
public string LevelName{ get; set; }
public bool IsProfessional { get; set; }
}
Finally:
var branch = new BranchResponse(); // Received filled from a gRPC call
// Read
var branchModel = new BranchModel
{
BranchId = Convert.ToInt32(branch.BranchId.NumberValue),
Level= new LevelModel
{
LevelId = Convert.ToInt32(branchModel.Level.StructValue.
Fields["LevelId"].NumberValue),
LevelName = branchModel.Level.StructValue.
Fields["LevelName"].StringValue,
IsProfessional = branchModel.Level.StructValue.
Fields["IsProfessional"].BoolValue,
}
};
I am writing a new app and I have chosen to use Java for flexibility. It is a GUI app so I will use JavaFX. This is my first time using Java but I have experience with C#.
I am getting familiar with JavaFX Properties, they look like a great way of bi-directional binding between front-end and back-end.
My code uses classes from an open-source API, and I would like to convert the members of these classes to JavaFX Properties (String => StringProperty, etc). I believe this would be transparent to any objects that refer to these members.
Is it ok to do this?
Is it the suggested way of dealing with existing classes?
What do I do about Enum types? E.g. an enum member has it's value changed, how should I connect the enum member to the front-end?
Thank you :)
In general, as long as you don't change the public API of the class - in other words you don't remove any public methods, modify their parameter types or return types, or change their functionality - you should not break any code that uses them.
So, e.g. a change from
public class Foo {
private String bar ;
public String getBar() {
return bar ;
}
public void setBar(String bar) {
this.bar = bar ;
}
}
to
public class Foo {
private final StringProperty bar = new SimpleStringProperty();
public StringProperty barProperty() {
return bar ;
}
public String getBar() {
return barProperty().get();
}
public void setBar(String bar) {
barProperty().set(bar);
}
}
should not break any clients of the class Foo. The only possible problem is that classes that have subclassed Foo and overridden getBar() and/or setBar(...) might get unexpected behavior if their superclass is replaced with the new implementation (specifically, if getBar() and setBar(...) are not final, you have no way to enforce that getBar()==barProperty().get(), which is desirable).
For enums (and other objects) you can use an ObjectProperty<>:
Given
public enum Option { FIRST_CHOICE, SECOND_CHOICE, THIRD_CHOICE }
Then you can do
public class Foo {
private final ObjectProperty<Option> option = new SimpleObjectProperty<>();
public ObjectProperty<Option> optionProperty() {
return option ;
}
public Option getOption() {
return optionProperty().get();
}
public void setOption(Option choice) {
optionProperty().set(choice);
}
}
One caveat to all this is that you do introduce a dependency on the JavaFX API that wasn't previously present in these classes. JavaFX ships with the Oracle JDK, but it is not a full part of the JSE (e.g. it is not included in OpenJDK by default, and not included in some other JSE implementations). So in practice, you're highly unlikely to be able to persuade the developers of the open source library to accept your changes to the classes in the library. Since it's open source, you can of course maintain your own fork of the library with JavaFX properties, but then it will get tricky if you want to incorporate new versions of that library (you will need to merge two different sets of changes, essentially).
Another option is to use bound properties in the classes, and wrap them using a Java Bean Property Adapter. This is described in this question.
(or "Using LocationInterceptionAspect and IInstanceScopedAspect together")
Using Postsharp I'm trying to inject a property into a target class using 'IntroduceMember' and then using the 'OnGetValue' functionality of LocationInterceptionAspect dynamically give it a value on inspection.
Originally I thought that I'd need two separate aspects, one for the field injection and one for the location interception but managed to combine the two by implementing the IInstanceScopedAspect interface and inheriting from LocationInterceptionAspect.
The problem is that if I set a breakpoint I will see the property that's been injected, but if I set another breakpoint in the OnGetValue method (that gets fired for each property on the class) I can't see it...
Here's some sample code:
[Serializable]
class DALDecoratorWrapper : LocationInterceptionAspect, IInstanceScopedAspect
{
public override void OnGetValue(LocationInterceptionArgs args)
{
if (args.LocationName == "Type")
{
args.Value = "computed value here";
}
args.ProceedGetValue();
}
[IntroduceMember(OverrideAction = MemberOverrideAction.OverrideOrFail)]
public String Type { get; set; }
I was also hoping there was a better way of doing this than overriding OnGetValue as that's called for each getter where really I want to only target the getter of the property that's been injected
Cheers
Is there any switch that instructs svcutil to generate DataContract properties with their names as defined in code? For example when I create a proxy which uses the following DataContract:
[DataContract(Namespace = "http://schemas.mynamespace.com/2012/08")]
public class MyDataContract
{
[DataMember(IsRequired = true, Order = 0)]
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
}
I get this DataContract on the proxy generated class:
public partial class MyDataContract : object
{
private int _idField;
[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
public int _id
{
get
{
return this._idField;
}
set
{
this._idField = value;
}
}
}
The order property of the DataMemberAttribute is always ommited as well for the first 3 properties and a MessageContract ommits an IDisposable implementation.
Well, I cannot comment on the omitted order, but I may be able to help on the rest:
One usually specifies the DataMember attribute on the property, not on the field. The data-contract itself does not distinguish between a property and a field, but it knows the name, type, if it is mandatory, etc. etc.
Added: What Chris said: With [DataMember(Name="whateveryouwant")] you'll be able to set a name different from the field/property name. I do not like such usage, though, but it is helpful when refactoring code, but still keeping the API compatible.
Only other DataContract (and some intrinsically supported) types are serialized to/from messages. IDisposable seems not to be one.
Serializing the inherited IDisposable of a MessageContract would not make any sense. A message-contract is the .NET representation of a SOAP message. It literally has nothing else to do but to provide a 1:1 mapping between what is in the SOAP message XML, and the accessible .NET types.
A message is part of a ServiceContract, in that it specifies which kind of message must be sent to a certain operation to be a valid invocation, and another (response-)message contract specifies how the data, that the operation returns, will be structured. Nothing else; it is a data-aggregate.
If you want to capture the result of a service-operation on the client, and for convenience automatically send a message back upon going out of scope (or for instance unregistering from a service), you will have to implement this on the client-side. Be aware, however, that the service must not require this to happen (due to lost connections, crashes, etc.).
Use the name property on DataMember attribute
Such as:
[DataMember(Name="myname")]
One of my WCF functions returns an object that has a member variable of a type from another library that is beyond my control. I cannot decorate that library's classes. In fact, I cannot even use DataContractSurrogate because the library's classes have private member variables that are essential to operation (i.e. if I return the object without those private member variables, the public properties throw exceptions).
If I say that interoperability for this particular method is not needed (at least until the owners of this library can revise to make their objects serializable), is it possible for me to use WCF to return this object such that it can at least be consumed by a .NET client?
How do I go about doing that?
Update: I am adding pseudo code below...
// My code, I have control
[DataContract]
public class MyObject
{
private TheirObject theirObject;
[DataMember]
public int SomeNumber
{
get { return theirObject.SomeNumber; } // public property exposed
private set { }
}
}
// Their code, I have no control
public class TheirObject
{
private TheirOtherObject theirOtherObject;
public int SomeNumber
{
get { return theirOtherObject.SomeOtherProperty; }
set { // ... }
}
}
I've tried adding DataMember to my instance of their object, making it public, using a DataContractSurrogate, and even manually streaming the object. In all cases, I get some error that eventually leads back to their object not being explicitly serializable.
Sure, write a wrapper class that has all of the same public properties available and simply put "get { return internalObject.ThisProperty; }. Decorate the wrapper class so that it works with WCF.
Another option is to write a Proxy class which mirrors the properties of the type you wish to use exactly, and return that via WCF.
You can use AutoMapper to populate the proxy object.
This approach has the advantage that your service's consumers don't need to take a dependency on the third party library in trying to use it.