I'm triying to read some data form an OPC UA server using opc-ua-client library. Managed to connect to server and read some simple variables, but facing issues when reading structured values. However, I'm able to browse those structured values using 3rd party tools, such as UAExpert.
This is the code snippet:
var readRequest = new ReadRequest
{
NodesToRead = new[] { new ReadValueId { NodeId = NodeId.Parse(nodeId), AttributeId = AttributeIds.Value } }
};
var response = channel.ReadAsync(readRequest).Result;
var result = response.Results[0].GetValueOrDefault<ExtensionObject>();
The point is: how should I cast the ExtensionObject into the underlying real object? Response's body is binary serialized into a System.Byte[] field, and don't know how to deserialize it. I know the fields and types of the structure, so defined it in the code (even decorating with the namespace provided by the server) as follow:
[BinaryEncodingId("nsu=urn:OMRON:NxOpcUaServer:FactoryAutomation;i=5005")]
private class MES_WRITE_STRUCT : Structure
{
uint Message_NUM { get; set; }
//Some other fields
DateTime Time_Stamp { get; set; }
}
Things I've tried (and failed) so far:
Brute-force cast:
var eObject = (MES_WRITE_STRUCT)result.GetValueOrDefault<ExtensionObject>();
Read the response as the expected type rather than using generic object:
var eObject = result.GetValueOrDefault<MES_WRITE_STRUCT>();
Use the Variant property rather than Value (same result as
using Value):
result.Variant.GetValue();
Create a binary reader and attempt to deserialize it into expected
class.
Maybe I'm using a wrong approach and structured values should be read in a different way. Or even the library does not support structured variables (not much documentation available). Or just using an incorrect type when defining custom class in .NET and hence casting is failing.
I'm totally stuck, any information or guidance is wellcome.
PS: I'm not tied to this library and can switch to another one (preferably with no licenses, but if really worths can consider buying).
One way would be to use the XML description of the information model (so called nodesets) you wish to consume and use the model compiler from OPC Foundation to generate C# classes out of it. Those classes can be integrated in your solution and used for deserialization.
And example (using the OPC Foundation libraries) could be found here
Another way is the OPC Foundation .NET Standard client which has an extension library nuget package called complex client. It contains the logic to read the structured type definition from a server from a dictionary (V1.03) or using DataTypeDefinition (V1.04).
Based on the obtained type definition the classes for the structured types can be emitted for encoding/decoding the byte string in the extension object at runtime. Please open issues if the complex client has difficulties to decode your structured type.
Related
I have this JSON:
{
"response":
{
"data":
[
{
"start":1,
"subjects":["A"]
},
{
"start":3,
"subjects":["B"]
},
{
"start":2,
"subjects":["C"]
}
]
}
}
And I want to get only the "subject" data from the object with it's "start" value to be the smallest one that is greater than 1.3, which in this case would be C. Would anybody happen to know how such a thing can be achieved using C#?
I want to extend a bit on the other answers and shed more light into the subject.
A JSON -- JavaScript Object Notation - is just a way to move data "on a wire". Inside .NET, you shouldn't really consider your object to be a JSON, although you may colloquially refer to a data structure as such.
Having said that, what is a JSON "inside" .NET? It's your call. You can, for instance treat it as a string, but you will have a hard time doing this operation of finding a specific node based on certain parameters/rules.
Since a JSON is a tree-like structure, you could build your on data structure or use the many available on the web. This is great if you are learning the workings of the language and programming in general, bad if you are doing this professionally because you will probably be reinventing the wheel. And parsing the JSON is not a easy thing to do (again, good exercise).
So, the most time-effective way of doing? You have two options:
Use a dynamic object to represent your JSON data. A dynamic is a "extension" to .NET (actually, an extension to the CLR, that is called DLR) which lets you create objects that doesn't have classes (they can be considered to be "untyped", or, better, to use duck typing).
Use a typed structure that you defined to hold your data. This is the canonical, object-oriented, .NET way of doing it, but there's a trade-off in declaring classes and typing everything, which is costly in terms of time. The payoff is that you get better intellisense, performance (DLR objects are slower than traditional objects) and more safe code.
To go with the first approach, you can refer to #YouneS answer. You need to add a dependency to your project, Newtonsoft.Json (a nuget), and call deserialize to convert the JSON string to a dynamic object. As you can see from his answer, you can access properties in this object as you would access then on a JavaScript language. But you'll also realize that you have no intellisense and things such as myObj.unexistentField = "asd" will be allowed. That is the nature of dynamic typed objects.
The second approach is to declare all types. Again, this is time consuming and on many cases you'll prefer not to do it. Refer to Microsoft Docs to get more insight.
You should first create your data contracts, as below (forgive me for any typos, I'm not compiling the code).
[DataContract]
class DataItem
{
[DataMember]
public string Start { get; set; }
[DataMember]
public string[] Subjects { get; set; }
}
[DataContract]
class ResponseItem
{
[DataMember]
public DateItem[] Data { get; set; }
}
[DataContract]
class ResponseContract
{
[DataMember]
public ResponseItem Response { get; set; }
}
Once you have all those data structures declared, deserialize your json to it:
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var deserializer = new DataContractJsonSerializer(typeof(ResponseContract));
return (T)deserializer.ReadObject(ms);
}
The code above may seem a bit complicated, but follow a bit of .NET / BCL standards. The DataContractJsonSerializer work only with streams, so you need to open a stream that contains your string. So you create a memory stream with all the bytes from the json string.
You can also use Newtonsoft to do that, which is much simpler but, of course, still requires that extra dependency:
DataContract contract = JsonConvert.DeserializeObject<DataContract>(output);
If you use this approach you don't need the annotations (all those DataMember and DataContract) on your classes, making code a bit more clean. I very much prefer using this approach than DataContractJsonSerializer, but it's your call.
I've talked a lot about serializing and deserializing objects, but your question was, "How do I find a certain node?". All the discussion above was just a prerequisite.
There are, again and as usual, a few ways of achieving what you want:
#YouneS answer. It's very straightforward and achieves what you are looking for.
Use the second approach above, and then use your typed object to get what you want. For instance:
var contract = JsonConvert.DeserializeObject<DataContract>(output);
var query = from dataItem in contract.Response.Data
where dataItem.Start > 1.3
order by dataItem.Start;
var item = query.FirstOrNull();
Which will return the first item which, since it's ordered, should be the smallest. Remember to test the result for null.
You can use a feature from Newtonsoft that enables to directly find the node you want. Refer to the documentation. A warning, it's a bit advanced and probably overkill for simple cases.
You can make it work with something like the following code :
// Dynamic object that will hold your Deserialized json string
dynamic myObj = JsonConvert.DeserializeObject<dynamic>(YOUR-JSON-STRING);
// Will hold the value you are looking for
string[] mySubjectValue = "";
// Looking for your subject value
foreach(var o in myObj.response.data) {
if(o.start > 1.3)
mySubjectValue = o.subjects;
}
I have a json String(array) like this:
[{"user":{"name":"abc","gender":"Male","birthday":"1987-8-8"}},
{"user":{"name":"xyz","gender":"Female","birthday":"1987-7-7"}}]
and want to parse it to json object using .net4.0 framework only, and i cannot use DataContractJsonSerializer as it requires class and i am receiving dynamic data over web services within 1 minute which keep changing and it is in Name-value format,i tried using JavaScriptSerializer but i am unable to add system.web.extension in my vs2010 project .net4.0 supported framework,and i don't want to use any third party library,actually i am New-bie in wpf,so please it would be great help,thanks in advance!
Well there are two main issues I can see here, and one additional.
1) If you do not have particular class that you could deserialize JSON to, then you have to rely on some "dictionary-like" structure (e.g. dynamic or JToken)to be able to access all fields. However data you presented seems to be structured, so maybe consider creating POCO to get advantage of strongly-typed structure. Both can be easily achieved using ready-to-use libraries.
2) You say you don't want to use any third party library, but actually there is nothing wrong with it. Actually you should be doing so to avoid reinventing the wheel as Tewr mentioned. It's perfectly fine to use in fact industry-standard library such as Newtonsoft Json so you can avoid tons of bugs, unnecessary work and future troubles. If your point is to learn by writing JSON (de)serializer it's perfectly fine, but I'd recommend against using it in production code.
Side note: you mentioned you receive data over web-service, and it seems you receive simply JSON array (as top-level object). It's considered as security hole. More information may be found here:
https://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/
What are "top level JSON arrays" and why are they a security risk?
EDIT 2017-11-05:
Ok, so you should create classes representing response from your web service (you can use feature of VS called Edit > Paste Special > Paste JSON As Classes):
public class Response
{
public User[] users { get; set; }
}
public class User
{
public string Name { get; set; }
public string gender { get; set; }
public string birthday { get; set; }
}
Now using Nuget install package Newtonsoft.Json and using following code you'll deserialize JSON response to .NET classes:
string responseText = "";//Get it from web service
var response = JsonConvert.DeserializeObject<Response>(responseText);
Hope this help!
I have defined a class and i need to store some objects of that class for future reference. Can i store these objects into an azure database i've created ?
In order to save an object (instance of a Class) to whatever medium (SQL Server, Azure SQL Database, Azure Table Storage, Blob Storage, local File System, whatever you come up with), you will need to serialize it. Then store the result of serialization to the medium of your choice. Next, when you want to use the persisted state of the object, you will have to deserialize it.
There are different serialization formatters, like XML, JSON, Binary, etc. Which one to use, depends on the where and how you are going to store the object. The most important however, is that, in order one object to be serialized, the defining Class should be marked with SerializableAttribute. And the drama begins when you want to serialize object which is part of 3rd partys API.
If it is your type - just mark it as Serializbale, serialize and store it. Pretty stright-forward process.
If you don't have access to the source code to explicitly mark class as Serializable, you could possibly use the Serialization Surrogate to serialize your object. But, you might have issues when deserializing. For example, if the API Class you use does not have a public contructor. Or if it does not provide setters for some of the properties, etc., etc. At the end, if a Type is not designed to be serializable, and is part of 3rd party API, there might be a ton of reasons serialization/deserialization might fail.
At the end, you could try using the Json.NET serializer (install via NuGet):
var someObj = new DummyClass
{
ID = Guid.NewGuid(),
IntID = 102934,
Name = "My Super Hero Name"
};
string json = JsonConvert.SerializeObject(someObj);
Console.WriteLine(json);
var otherObj = JsonConvert.DeserializeObject<DummyClass>(json);
Console.WriteLine(otherObj.ID);
Console.ReadKey();
and check if it correctly serializes/deserializes your object. If everything is fine - use the json string to save it into Database of your choice.
I have a simple class like
public class Customer{
public long Id;
public string Name;
....
}
I have a List and I want to serialize it using protobuf-net. Please guide me simple and efficient way of serializing and de-serializing this.
EDIT-1
I was looking at the unit test available with the protobuf-net source code, it uses 2 ways to serialize, using reflection and with Model (which internally handles the mapping based on ToString).
What I followed from the source code is that I used the same technique as tested in the project folder e-ProtoBufNetWithModel of the source code and created a TypeModel...
public static TypeModel CreateModel()
{
RuntimeTypeModel model = TypeModel.Create();
model.Add(typeof(Customer), false)
.Add(1, "Id")
.Add(1, "Name");
TypeModel compiled = model.Compile();
return compiled;
}
Problem Area
public static Stream SerializeUsingProtobuf(IList<Customer> pSource)
{
var model = CreateModel();
using (Stream memoryStream = new MemoryStream())
{
model.Serialize(memoryStream, pSource);
return memoryStream;
}
}
On TypeModel compiled = model.Compile();, it raises exception
Duplicate field-number detected; 1
Each field to serialize requires a different tag (a positive integer). Instead of 1 and 1, try using 1 and 2 when calling Add. Or simpler, just Add("Id", "Name");
https://code.google.com/p/protobuf-net/
The short version
(see also the old home page)
Serialization is a pain. protobuf-net is designed to be easily used on your existing code with minimal changes (of from an optional .proto schema), enabling fast and portable binary serialization on a wide range of .NET platforms.
Rather than being "a protocol buffers implementation that happens to be on .NET", it is a ".NET serializer that happens to use protocol buffers" - the emphasis is on being familiar to .NET users (for example, working on mutable, code-first classes if you want). I've also added a range of commonly requested features beyond the regular protobuf design, to help meet the every-day demands of .NET programmers (inheritance, reference-tracking, etc).
Usage is very simple; at the most basic level, simply read from a stream or write to a stream; see Getting Started:
// write to a file
Serializer.Serialize(outputStream, person);
...
// read from a file
var person = Serializer.Deserialize<Person>(inputStream);
Oh, and it is very fast; both in CPU and in bandwidth.
There is some VS tooling if you want to work from .proto files in visual studio, but you don't need that - you can just write a class, tell the serializer how to work with it (most commonly by adding a few attributes, but that is up to you), and serialize away.
https://code.google.com/p/protobuf-net/wiki/GettingStarted
Serializing Data
Since "protocol buffers" is a binary format, protobuf-net is based heavily around the Stream class; this makes it possible to use with a wide variety of implementations simply. For example, to write to a file:
var person = new Person {
Id = 12345, Name = "Fred",
Address = new Address {
Line1 = "Flat 1",
Line2 = "The Meadows"
}
};
using (var file = File.Create("person.bin")) {
Serializer.Serialize(file, person);
}
This writes a 32 byte file to "person.bin". It might not be obvious in the above, but Serialize is a generic method - the line could also be:
using (var file = File.Create("person.bin")) {
Serializer.Serialize<Person>(file, person);
}
But most of the time we can let the compiler's generic type inference do the work for us.
Deserializing Data
We also need to get out data back!
Person newPerson;
using (var file = File.OpenRead("person.bin")) {
newPerson = Serializer.Deserialize<Person>(file);
}
This reads the data back from "person.bin". Note we need to tell it the type this time (the ), but otherwise the code is very similar.
I can use the .Net ConfigurationManager to store strings, but how can I store structured data?
For example, I can do this:
conf = ConfigurationManager.OpenExeConfiguration(...)
string s = "myval";
conf.AppSettings.Settings["mykey"].Value = s;
conf.Save(ConfigurationSaveMode.Modified);
And I would like to do this:
class myclass {
public string s;
int i;
... more elements
};
myclass c = new myclass(); c.s = "mystring"; c.i = 1234; ...
conf.AppSettings.Settings["mykey"] = cc;
conf.Save(ConfigurationSaveMode.Modified);
How do I store and retrieve structured data with the ConfigurationManager?
I implemented a solution as #sll suggested. But then difficulty was to create a new section to the configuration. Here is how this is done:
How to Write to a User.Config file through ConfigurationManager?
You can create own configuration section type by inheriting from ConfigurationSection class and use it to save/load any custom type information.
MSDN: How to: Create Custom Configuration Sections Using ConfigurationSection
BTW, One advice which might be helpful for you or others: One good thing is making custom configurations section class immutable (no public setters) so you can be sure that configuration cannot be changed on any stage of application life cycle, but then if you decide writing unit tests for code which relies on configuration section class and need section stub with some test values you might stuck with abilty to set property values since there is no setters. Solution is providing a new class which is inherited from your section class and specifying in constructor values using protected indexer like show below:
public class TestSectionClass: MyConfigurationSection
{
public TestSectionClass(string testUserName)
{
this["userName"] = testUserName;
}
}
Serialization.
There are numerous different ways of serializing data, so you'd need to pick one. But .NET provides a serialization API that suits a great many cases, and in working with web AJAX calls recently I find myself using JavaScriptSerializer heavily to turn things into JSON. However there are third party libraries such as protobuf-net, and so on.
The key here is to essentially turn your data into a byte or string representation that can later be deserialized back to its original structure at a later date, allowing you to store it in a medium between then, such as in configuration files or transmission over networks etc.
As per #sll's answer, .NET has another facet meaning it can handle serialization of data in and out of custom configuration sections; whether you want to begin specifying types explicitly for this purpose or not is your call. Bottom line is the same, serialize, somehow.