nhapi - Modifiy a segment value - c#

Env :
Visual Studio 2013,
Winform / C# / Framework 4.5,
nHapi DLL 2.4.0.9,
HL7 Version 2.3
I'm building a little windows application that read HL7 messages and send them to an Interface system.
Everything is working just fine but I would like to know if it's possible to replace/add/modify a segment value : EVN 5.2 (Operator ID / Family name).
At the moment, I'm reading the content of the HL7 file on the computer, put the content in a string, parse the message, encode the message and return it.
public static String ParseMessage(String message)
{
var parser = new NHapi.Base.Parser.PipeParser();
var parsedMessage = parser.Parse(message);
/* I guess it's here that I should do the change for the EVN 5.2 ? But How ;-) */
var msgType = parsedMessage.GetStructureName();
var pipeDelimitedMessage = parser.Encode(parsedMessage);
return pipeDelimitedMessage;
}
Thanks everyone for you help
Richard

The way the nHapi would have you do this is cast the 'parsed' abstract message down to its concrete type so that you are able to walk the object model and set the properties you'd like.
As an example, take the case of an ADT A01 admit message:
[Test]
public void TestPopulateEVNOperaterID()
{
string message = #"MSH|^~\&|SUNS1|OVI02|AZIS|CMD|200606221348||ADT^A01|1049691900|P|2.3
EVN|A01|200601060800
PID||8912716038^^^51276|0216128^^^51276||BARDOUN^LEA SACHA||19981201|F|||AVENUE FRANC GOLD 8^^LUXEMBOURGH^^6780^150||053/12456789||N|S|||99120162652||^^^|||||B
PV1||O|^^|U|||07632^MORTELO^POL^^^DR.|^^^^^|||||N||||||0200001198
PV2|||^^AZIS||N|||200601060800
IN1|0001|2|314000|||||||||19800101|||1|BARDOUN^LEA SACHA|1|19981201|AVENUE FRANC GOLD 8^^LUXEMBOURGH^^6780^150|||||||||||||||||ZIN|0164652011399|0164652011399|101|101|45789^Broken bone";
var parser = new PipeParser();
var abstractMessage = parser.Parse(message);
// this is the normal / expected way of working with NHapi parsed messages
var typedMessage = abstractMessage as ADT_A01;
if (typedMessage != null)
{
typedMessage.EVN.OperatorID.FamilyName.Value = "Surname";
typedMessage.EVN.OperatorID.GivenName.Value = "Firstname";
}
var pipeDelimitedMessage = parser.Encode(typedMessage);
// alternatively, you can apply this modification to any HL7 2.3 message
// with an EVN segment using this more generic method
var genericMethod = abstractMessage as AbstractMessage;
var evn = genericMethod.GetStructure("EVN") as EVN;
if (evn != null)
{
evn.OperatorID.FamilyName.Value = "SurnameGeneric";
evn.OperatorID.GivenName.Value = "FirstnameGeneric";
}
pipeDelimitedMessage = parser.Encode(typedMessage);
}
I believe the second more generic way is probably what you'll be wanting for this case, however I thought I'd just show you as well how to get to parsed / concrete type so that you can work with it that way if you are dealing with a specific message type.

Related

The right way to send generic data types with protobuf3 in C#/.NET

I'm developing an application using a plugins architecture and I want to send objects between client and server without knowing the type of the object being sent.
Is there a way to send generic data type ?
According to Microsoft pages, the Any field could be an answer to this problem, instead of using a string and a custom serialization/deserialization implementation to send these objects. However, I didn't find the provided c# examples understandable. I tried to solve the problem this way:
ClassTest myClassTest = new ClassTest();
Any packToSend = Any.Pack(myClassTest);
return Task.FromResult(new UnknownTEST
{
Pathm = hai
}); ;
But it seems that I need to implement the IMessage interface in my class and I don't know how to do this.
If anyone could provide a basic example to help me understand how to do this, that would be great.
Thanks !
You need to create protobuf messages which represent the data you're sending. You don't need to create your own classes as you did with your "ClassTest" class.
Here's an example:
point.proto:
syntax = "proto3";
option csharp_namespace = "MyProject.Namespace";
message Point {
int32 x = 1;
int32 y = 2;
}
generic_dto_message.proto:
syntax = "proto3";
import "google/protobuf/any.proto";
option csharp_namespace = "MyProject.Namespace";
message GenericDtoMessage {
google.protobuf.Any data = 1;
}
C# code:
// packing
var point = new Point
{
X = 1,
Y = 22
};
var genericDtoMessage = new GenericDtoMessage();
genericDtoMessage.Data = Any.Pack(point);
// unpacking
var unpackedData = genericDtoMessage.Data.Unpack<Point>();
Console.WriteLine($"X: {unpackedData.X}{Environment.NewLine}Y: {unpackedData.Y}");
Console.WriteLine($"Press any key to continue...");
Console.ReadKey();
In case you are using Grpc.Tools NuGet package to generate C# code for the above written .proto files, don't forget to add this ItemGroup section to your .csproj file:
<ItemGroup>
<Protobuf Include="point.proto" Link="point.proto" />
<Protobuf Include="generic_dto_message.proto" Link="generic_dto_message.proto" />
</ItemGroup>
Hope it helps!

How to serialize tensor input required by dnnclassifier (serving_input_reciever)

I want to be able to use the dnnclassifier (estimator) on top of IIS using tensorflowsharp. The model has previously been trained in python. I got so far that I can now generate PB files, know the correct input/outputs, however I am stuck in tensorflowsharp using string inputs.
I can create a valid .pb file of the iris dataset. It uses the following feate_spec:
{'SepalLength': FixedLenFeature(shape=(1,), dtype=tf.float32, default_value=None), 'SepalWidth': FixedLenFeature(shape=(1,), dtype=tf.float32, default_value=None), 'PetalLength': FixedLenFeature(shape=(1,), dtype=tf.float32, default_value=None), 'PetalWidth': FixedLenFeature(shape=(1,), dtype=tf.float32, default_value=None)}
I have created a simple c# console to try and spin it up. The input should be an "input_example_tensor" and the output is located in "dnn/head/predictions/probabilities". This I discoved after alex_zu provided help using the saved_model_cli command here.
As far as I am aware all tensorflow estimator API's work like this.
Here comes the problem: the input_example_tensor should be of a string format which will be parsed internally by the ParseExample function. Now i am stuck. I have found TFTensor.CreateString, but this doesn't solve the problem.
using System;
using TensorFlow;
namespace repository
{
class Program
{
static void Main(string[] args)
{
using (TFGraph tfGraph = new TFGraph()){
using (var tmpSess = new TFSession(tfGraph)){
using (var tfSessionOptions = new TFSessionOptions()){
using (var metaGraphUnused = new TFBuffer()){
//generating a new session based on the pb folder location with the tag serve
TFSession tfSession = tmpSess.FromSavedModel(
tfSessionOptions,
null,
#"path/to/model/pb",
new[] { "serve" },
tfGraph,
metaGraphUnused
);
//generating a new runner, which will fetch the tensorflow results later
var runner = tfSession.GetRunner();
//this is in the actual tensorflow documentation, how to implement this???
string fromTensorflowPythonExample = "{'SepalLength': [5.1, 5.9, 6.9],'SepalWidth': [3.3, 3.0, 3.1],'PetalLength': [1.7, 4.2, 5.4],'PetalWidth': [0.5, 1.5, 2.1],}";
//this is the problem, it's not working...
TFTensor rawInput = new TFTensor(new float[4]{5.1f,3.3f,1.7f,0.5f});
byte[] serializedTensor = System.Text.Encoding.ASCII.GetBytes(rawInput.ToString());
TFTensor inputTensor = TensorFlow.TFTensor.CreateString (serializedTensor);
runner.AddInput(tfGraph["input_example_tensor"][0], inputTensor);
runner.Fetch("dnn/head/predictions/probabilities", 0);
//start the run and get the results of the iris example
var output = runner.Run();
TFTensor result = output[0];
//printing response to the client
Console.WriteLine(result.ToString());
Console.ReadLine();
}
}
}
}
}
}
}
This example will give the following error:
An unhandled exception of type 'TensorFlow.TFException' occurred in TensorFlowSharp.dll: 'Expected serialized to be a vector, got shape: []
[[Node: ParseExample/ParseExample = ParseExample[Ndense=4, Nsparse=0, Tdense=[DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT], dense_shapes=[[1], [1], [1], [1]], sparse_types=[], _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_input_example_tensor_0_0, ParseExample/ParseExample/names, ParseExample/ParseExample/dense_keys_0, ParseExample/ParseExample/dense_keys_1, ParseExample/ParseExample/dense_keys_2, ParseExample/ParseExample/dense_keys_3, ParseExample/Const, ParseExample/Const, ParseExample/Const, ParseExample/Const)]]'
How can I serialize tensors in such a way that I can use the pb file correctly?
I also posted the issue on github, here you can find the iris example python file, pb file and the console applications. In my opinion solving this creates a
neat solution for all tensorflow users having ancient production environments (like me).
The Expected serialized to be a vector, got shape: [] error can be fixed by using an overload of the TFTensor.CreateString function: Instead of directly taking a string, the model apparently expects a vector containing a single string:
TFTensor inputTensor = TFTensor.CreateString(new byte[][] { bytes }, new TFShape(1));
The input_example_tensor in your case now expects a serialized Example protobuf message (see also the docs and the example.proto file).
Using the protobuf compiler, I've generated a C# file containing the Example class. You can download it from here: https://pastebin.com/iLT8MUdR. Specifically, I used this online tool with CSharpProtoc and replaced the import "tensorflow/core/example/feature.proto"; line by the messages defined in that file.
Once you've added the file to your project, you'll need a package reference to Google.Protobuf. Then, you can pass serialized examples to the model like this:
Func<float, Tensorflow.Feature> makeFeature = (float x) => {
var floatList = new Tensorflow.FloatList();
floatList.Value.Add(x);
return new Tensorflow.Feature { FloatList = floatList };
};
var example = new Tensorflow.Example { Features = new Tensorflow.Features() };
example.Features.Feature.Add("SepalLength", makeFeature(5.1f));
example.Features.Feature.Add("SepalWidth", makeFeature(3.3f));
example.Features.Feature.Add("PetalLength", makeFeature(1.7f));
example.Features.Feature.Add("PetalWidth", makeFeature(0.5f));
TFTensor inputTensor = TFTensor.CreateString(
new [] { example.ToByteArray() }, new TFShape(1));
runner.AddInput(tfGraph["input_example_tensor"][0], inputTensor);
runner.Fetch("dnn/head/predictions/probabilities", 0);
//start the run and get the results of the iris example
var output = runner.Run();
TFTensor result = output[0];

Api for working with a classes as OOP?

I'm writing a 3rd party app that needs to read in .cs files and be able to manipulate classes, then ultimately save back to file.
The type of code I am looking at would be something like:
var classManager = new classManager();
var classes = classManager.LoadFromFile(filePath);
var class = classes[0]; // Just illustrating more than 1 class can exist in a file
var prop = new ClassProperty {Type=MyType.GetType() };
prop.AddGet("return x+y < 50");
//stuff like prop.ReadOnly = true;
class.AddProperty(prop);
var method = new ClassMethod {signature="int id, string name"};
method.MethodBody = GetMethodBodyAsString(); //not writing out an entire method body here
class.AddMethod(method);
class.SaveToFile(true); //Format code
Does such a library exist?
The .NET Compiler Platform Roslyn is what you're looking for. It supports parsing and editting cs files. Check out this post for an example

Is it possible to execute C# code represented as string?

On my form I have a button click
private void button1_Click(object sender, EventArgs e)
{
do something
}
How on the click would I load my do something from a text file, for example my text file looks like this:
MessageBox.Show("hello");
label1.Text = "Hello";
on click it does everything in my text file, if possible.
Here is a very simple example, just to prove this is possible. Basically, you use CodeDomProvider to compile source at runtime, then execute using reflection.
var provider = CodeDomProvider.CreateProvider("C#");
string src=#"
namespace x
{
using System;
public class y
{
public void z()
{
Console.WriteLine(""hello world"");
}
}
}
";
var result = provider.CompileAssemblyFromSource(new CompilerParameters(), src);
if (result.Errors.Count == 0)
{
var type = result.CompiledAssembly.GetType("x.y");
var instance = Activator.CreateInstance(type);
type.GetMethod("z").Invoke(instance, null);
}
Edit
As #Agat points out, the OP seems to require a sort of scripting framework (it makes use of label1, a property of the current object), whereas my answer above obviously does not provide that. The best I can think of is a limited solution, which would be to require dependencies to be specified explicitly as parameters in the "script". Eg, write the scripted code like this:
string src = #"
namespace x
{
using System.Windows;
public class y
{
public void z(Label label1)
{
MessageBox.Show(""hello"");
label1.Text = ""Hello"";
}
}
}
";
Now you can have the caller examine the parameters, and pass them in from the current context, again using reflection:
var result = provider.CompileAssemblyFromSource(new CompilerParameters(), src);
if (result.Errors.Count == 0)
{
var type = result.CompiledAssembly.GetType("x.y");
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("z");
var args = new List<object>();
// assume any parameters are properties/fields of the current object
foreach (var p in method.GetParameters())
{
var prop = this.GetType().GetProperty(p.Name);
var field = this.GetType().GetField(p.Name);
if (prop != null)
args.Add(prop.GetValue(this, null));
else if (field != null);
args.Add(field.GetValue(this));
else
throw new InvalidOperationException("Parameter " + p.Name + " is not found");
}
method.Invoke(instance, args.ToArray());
}
Like the other answers have stated, it isn't an easy thing to implement and can possibly be done through reflection depending on how advanced your scripts are.
But no one #BrankoDimitrijevic mentioned Roslyn and it is a great tool. http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx
It hasn't been updated in quite awhile (Sept.2012) and doesn't have all of the features of C# implemented, however, it did have a lot of it implemented when I played around with this release.
By adding your assembly as a reference to the scripting session, you're able to gain access to all of your assembly's types and script against them. It also supports return values so you can return any data that a scripted method generates.
You can find what isn't implemented here.
Below is a quick and dirty example of Roslyn that I just wrote and tested. Should work right out of box after installing Roslyn from NuGet. The small bloat at the initialization of the script engine can easily be wrapped up in a helper class or method.
The key is passing in a HostObject. It can be anything. Once you do, your script will have full access to the properties. Notice that you just call the properties and not the host object in the script.
Basically, your host object will contain properties of the data you need for your script. Don't necessarily think of your host object as just a single data object, but rather a configuration.
public class MyHostObject
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public class RoslynTest
{
public void Test()
{
var myHostObject = new MyHostObject
{
Value1 = "Testing Value 1",
Value2 = "This is Value 2"
};
var engine = new ScriptEngine();
var session = engine.CreateSession(myHostObject);
session.AddReference(myHostObject.GetType().Assembly.Location);
session.AddReference("System");
session.AddReference("System.Core");
session.ImportNamespace("System");
// "Execute" our method so we can call it.
session.Execute("public string UpdateHostObject() { Value1 = \"V1\"; Value2 = \"V2\"; return Value1 + Value2;}");
var s = session.Execute<string>("UpdateHostObject()");
//s will return "V1V2" and your instance of myHostObject was also changed.
}
}
No. You can not.
At least in any simple way.
The thing you want is something like eval('do something') from javascript.
That's not possible to do with C#. C# is a language which needs compilation before execution unlike javascript (for instance).
The only way to implement that is to build your own (pretty complicated as for beginner) parser and execute it in such way.
UPDATED:
Actually, as JDB fairly noticed, that's really not the only way. I love programming! There are so many ways to make a freakky (or even sometimes that really can be necessary for some custom interesting tasks (or even learning)!) code. he he
Another approach I've got in my mind is building some .cs file, then compiling it on-the-fly and working with it as some assembly or some other module. Right.

Currency Convertor Web Service

I am trying to make use of a currency conversion web service in my website. I have added a reference to the .asmx file.
Here is my code:
net.webservicex.www.CurrencyConvertor Convertor; //creating instance of web service
float new_donation = donation * Convertor.ConversionRate("EUR", "GBP"); //converting donation to new value
The problem is that the second line I posted is giving me the following errors:
The best overloaded method match for 'abc.net.webservicex.www.CurrencyConvertor.ConversionRate(abc.net.webservicex.www.Currency, abc.net.webservicex.www.Currency)' has some invalid arguments
Argument 1: cannot convert from 'string' to 'abc.net.webservicex.www.Currency'
Argument 2: cannot convert from 'string' to 'abc.net.webservicex.www.Currency'
Here is the link to the web service description:
http://www.webservicex.net/ws/wsdetails.aspx?wsid=10
How can I solve this problem? Thank you in advance.
It's telling you clear as day... you're passing in 2 strings to you're ConversionRate(...) method when it is expecting 2 Currencys.
This seems like it might not be a WebService you are in control of, but just a consumer of...
First, the easiest way to handle consuming this WebService is to use the "Add Service Reference..." in your project (WSDL Address: http://www.webservicex.net/CurrencyConvertor.asmx?WSDL) ...
But, if you want to do it manually then create an enumeration to use and pass in an enumeration value...
public enum Currency
{
AFA,
ALL,
...
}
Convertor.ConversionRate(Currency.EUR, Currency.GBP);
Instead of use string "EUR" use Convertor.Currency.EUR.
I'm pretty new to C# and WPF so I went through the same phase as you did.
Let me try to give a step by step method to make it work.
As some of the other posts said already, first you will need to add the web reference. You can do this by going to your Solution Explorer, right click on "Service References", and click "Add Service Reference". In the new window, click "Advanced" at the bottom, and in the next window click "Add Web Reference" at the bottom. Then type URL:
"http://www.webservicex.net/CurrencyConvertor.asmx?WSDL"
Normally by now it should be looking for available services related to this URL, and find one: "CurrencyConverter". Give it a reference name such as "net.webservicex.www" and click "Add Reference". Now you can use it in your code.
Let's go to the code now. If you would like to display, for example, the Euro / US Dollar exchange rate, all you need is this code:
net.webservicex.www.CurrencyConvertor conver = new net.webservicex.www.CurrencyConvertor();
MessageBox.Show((conver.ConversionRate(net.webservicex.www.Currency.EUR, net.webservicex.www.Currency.USD)).ToString());
conver.dispose();
Hope this helps!
I wrote this a while back, I call the current currencies and store them in the class as the json object. This makes calculations across multiple currencies faster as you are doing on the platform.
getCurrencies -> returns string[] "EUR","USD" etc
calculate -> ("USD","EUR",1.0) converts 1 dollar into euros
class CurrencyConvertor
{
public string[] currencyList;
RestClient client = new RestClient ("http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json");
RestRequest request = new RestRequest ("",Method.GET);
JObject json;
public CurrencyConvertor()
{
var response = client.Execute(request);
json = JObject.Parse (response.Content);
}
public string[] getCurrencies()
{
ArrayList currencies = new ArrayList ();
foreach (var item in json["list"]["resources"]) {
string tempN = item ["resource"] ["fields"] ["name"].ToString ().Replace ("USD/", "");
if(tempN.Length < 4)
currencies.Add (tempN);
}
currencies.Sort ();
currencyList = (string[])currencies.ToArray(typeof(string));
return currencyList;
}
public string calculate(string Base, string Target, decimal amount)
{
decimal temp1 = 1;
decimal temp2 = 1;
Console.WriteLine (Base + "to"+Target);
foreach (var item in json["list"]["resources"]) {
if (item["resource"]["fields"]["name"].ToString().Contains("/"+Base)) {
temp1 = decimal.Parse(amount.ToString()) * decimal.Parse(item ["resource"] ["fields"] ["price"].ToString(), CultureInfo.InvariantCulture.NumberFormat);
}
if (item ["resource"] ["fields"] ["name"].ToString().Contains("/"+Target)) {
temp2=decimal.Parse(amount.ToString()) * decimal.Parse(item ["resource"] ["fields"] ["price"].ToString(), CultureInfo.InvariantCulture.NumberFormat);
}
}
var dec = ((decimal)temp2 / (decimal)temp1);
return (Math.Round(dec*amount,5) ).ToString().Replace(",",".");
}
}

Categories

Resources