Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOAP over serial (RS-485) possible? #1127

Open
svenwanzenried opened this issue Mar 20, 2025 · 3 comments
Open

SOAP over serial (RS-485) possible? #1127

svenwanzenried opened this issue Mar 20, 2025 · 3 comments

Comments

@svenwanzenried
Copy link

Hi
A measurement device that I need to control speaks SOAP-over-serial. I have no control over that. The SOAP XML string gets placed into a custom message frame containing a sequence id as well as a checksum. This message frame is then sent over RS485 and the answer returns in a identical message frame. Here is an excerpt from the protocol specification:

Image

I managed to get this specific message working. I also have a custom encoder for the message frame. What I am missing now is an easy Implementation of the dozens of additional function calls the measurement device supports.
I have a WSDL file that specifies the whole interface.

So my questions to this project are:

  • Is it possible to somehow replace the physical layer of web traffic by my implementation of the serial interface?
  • Is it possible to format the messages according to the XML specified in the documentation and also parse the answer correctly?
    I would also be happy if the Project just provided a Function to generate the XML from a Function call and then let me handle the transmission. And another function that would let me parse back my received answer?
@andersjonsson
Copy link
Collaborator

I can see two possible solutions:

  1. You could read the incoming messages yourself and pass it on to the web layer. Then you take the response and pass that back to the device.
    Unless you have very high performance requirements, that should work nicely.

  2. If you need better performance, you can create an instance of SoapEndpointMiddleware and call Invoke on it.
    However, you'd have to fake an HttpContext that the incoming message can be read from and the response can be written to.
    I have no idea how easy this approach would be and if you'd run into blocking issues.

If you have an Idea about how to make this kind of scenario easier, please feel free to submit a PR

@svenwanzenried
Copy link
Author

I'm not sure I understand your suggestions. But I appreciate the swift reply, thanks!
Performance is really of no issue here, so I like the sound of your 1st solution. However I'm not sure if we are on the same page regarding the communication direction. What I would wish for is this sequence:

  1. I get a proxy class, or client from the WSDL file. (I'm not sure how to go about that, so that the generated code would be compatible with SoapCore)
  2. I can call the member of this proxy class GetCounterId() or similar
  3. SoapCore would generate XML that i somehow can get back
  4. I would encode this XML string myself into the serial message frame and send it over serial
  5. I receive a message frame back and extract the response XML string
  6. I pass this string to SoapCore somehow and then get back the C# object "GetCounterIdResponse" or similar.

Did you also have this sequence in mind when suggesting solution 1?
Maybe you could give my some pointers where to start. E.g. at what objects I would have to look, or which classes i would have to implement myself?

@andersjonsson
Copy link
Collaborator

Gotcha! I misunderstood your scenario. I thought you needed to write a backend that could respond to requests from the device.

SoapCore doesn't have code for generating the requestmessage, since that is supposed to be sent as an incoming payload to SoapCore.

I don't think that SoapCore is a good fit for your scenario.

You would probably be better off using wsdl.exe to generate c# classes from you wsdl.

Then include the package System.ServiceModel.Primitives and use the MessageClass to build your request message.

You can use something like this (.Dump() is a linqpad feature that just prints the value)

void Main()
{
	var req = new CounterGetIdRequest() { MyInt = 7, MyString = "Hello World!"};
	
	var serializer = new XmlSerializer(typeof(CounterGetIdRequest));
	
	var ms = new MemoryStream();
		
	serializer.Serialize(ms, req);
	ms.Position = 0;
	var xr = XmlReader.Create(ms);
	
	var message = Message.CreateMessage(MessageVersion.Soap12, null, xr);
	//Message created


	//Get string from message
	using var resultStream = new MemoryStream();
	using (var xw = XmlWriter.Create(resultStream, new XmlWriterSettings() { Indent = true }))
	{
		message.WriteMessage(xw);
	}
	
	var messageString = Encoding.Default.GetString(resultStream.ToArray());
	
	//Send this string (or probably just the array from resultStream) to your device
	messageString.Dump();
	
	
}

[Serializable]
[XmlType(TypeName = "Counter.GetId")]
public class CounterGetIdRequest
{
	[XmlAttribute("MyInt")]
	public int MyInt;
	
	public string MyString;
}

The response from the device can be parsed by Message.Create. Then you call GetReaderAtBodyContents and pass that to the xmlSerializer, to deserialize into the expected object type

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants