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

Overloads of Message.CreateMessage() that take an Xml(...)Reader argument produce invalid body #5717

Open
ZzZombo opened this issue Dec 18, 2024 · 0 comments

Comments

@ZzZombo
Copy link

ZzZombo commented Dec 18, 2024

Describe the bug
I have the same issue as described at https://microsoft.public.dotnet.framework.webservices.narkive.com/n9xIRs39/modified-message-body-in-beforesendrequest-iclientmessagein-is-e. Calling any such overload invariably produces ...stream... where stream is localized into what the runtime believes to be the culture of the machine instead of the body of the message. Now, I tried to follow the tip left on that page and create my own Message class overriding OnWriteBodyContents(XmlDictionaryWriter writer) only to find out that it is NOT called by WCF at all. However, somehow it now outputs just ... in the same place.

To Reproduce

public class CorrectorInspector: IClientMessageInspector
{
	private class MyMessage: Message
	{
		private XmlReader xmlReader1;
		private Message request;

		public MyMessage(XmlReader xmlReader1, Message request)
		{
			this.xmlReader1 = xmlReader1;
			this.request = request;
		}

		public override MessageHeaders Headers => this.request.Headers;

		public override MessageProperties Properties => this.request.Properties;

		public override MessageVersion Version => this.request.Version;

		protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
		{
			// Breakpoints are not hit.
			var _reader = this.xmlReader1;
			using(_reader)
			{
				var type = _reader.MoveToContent();
				while(!_reader.EOF && type != XmlNodeType.EndElement)
				{
					if(type != XmlNodeType.Element)
						throw new InvalidOperationException();
					writer.WriteNode(_reader, false);

					type = _reader.MoveToContent();
				}
			}
		}
		
	}

	private static readonly XNamespace urn = "urn:service";
	private static readonly XNamespace env = "http://schemas.xmlsoap.org/soap/envelope/";
	public void AfterReceiveReply(ref Message reply, object correlationState) { }

	public object? BeforeSendRequest(ref Message request, IClientChannel channel)
	{
		var msgbuf = request.CreateBufferedCopy(int.MaxValue);

		using var tmpMessage = msgbuf.CreateMessage();
		using var ms = new MemoryStream();
		using var writer = XmlWriter.Create(ms, new XmlWriterSettings { OmitXmlDeclaration = true, NamespaceHandling = NamespaceHandling.OmitDuplicates });
		tmpMessage.WriteMessage(writer);
		writer.Flush();

		ms.Position = 0;
		var xml = XDocument.Load(ms);

		xml.Root!.Add(new XAttribute(XNamespace.Xmlns + "urn", urn));

		var header = xml.Root.Element(env + "Header")!;
		header.RemoveNodes();

		var body = xml.Root.Element(env + "Body")!;
		body.RemoveAttributes();

		var action = (XElement)body.FirstNode!;
		action.RemoveAttributes();
		action.Name = urn + action.Name.LocalName;
		foreach(var param in action.Elements())
		{
			param.Name = param.Name.LocalName;
			param.RemoveAttributes();
		}

		var newMessage = new MyMessage(xml.CreateReader(), request);
		// Previously the above line was
        //var newRequest = Message.CreateMessage(xml.CreateReader(), int.MaxValue, request.Version);
        //newMessage.Headers.CopyHeadersFrom(oldMessage);
        //newRequest.Properties.CopyProperties(request.Properties);
		request = newMessage; // Breakpoint at this line reveals upon inspection of `newMessage` that the body tag has the unexpected value.
		return null;
	}
}

Expected behavior
The message body, as a part of the whole message, is correctly replaced with the new XML.

Screenshots
I can do on request.

Additional context
The current behavior might be by design. https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.message.createmessage?view=net-8.0-pp&devlangs=csharp&f1url=%3FappId%3DDev17IDEF1%26l%3DEN-US%26k%3Dk%28System.ServiceModel.Channels.Message.CreateMessage%29%3Bk%28DevLang-csharp%29%26rd%3Dtrue#system-servicemodel-channels-message-createmessage(system-xml-xmlreader-system-int32-system-servicemodel-channels-messageversion) remarks that it reads up to the body of the message. However, it doesn't explain how are we supposed to provide the body of the message then, neither there is any API that I could find myself for that, and all my Internet search results say in unison that this is how you change the message in an inspector w/o mentioning this pitfall, nor can I see how is outputting the literal string of ...stream... (localized) in the modified response is helpful, and the other overloads taking an Xml(...)Reader instance do not have this note, but are still affected all the same. Either way, there is an issue to be resolved.

I have tried many different combinations of streams and writers in every overload.

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

1 participant