Web Service Serialization produces an unwanted root in SOAP body - web-services

History:
A WSDL was provided to me with which I generated a service reference.
The object to serialize and send to the web service to consume, was a strongly, complex-typed class.
Instead of sending a strongly, complex-typed class, I wanted to send an XMLDocument instead.
So I modified the service and I am left with this:
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.17929")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name = "B2MML_ProcessProductionPerformance_MaterialConsumption_OBBinding", Namespace="http://company.com/M2D/Manufacturing/ManufacturingExecution/GoodsIssue/pi")]
public partial class B2MML_ProcessProductionPerformance_MaterialConsumption_OBService : System.Web.Services.Protocols.SoapHttpClientProtocol {
private System.Threading.SendOrPostCallback B2MML_ProcessProductionPerformance_MaterialConsumption_OBOperationCompleted;
public B2MML_ProcessProductionPerformance_MaterialConsumption_OBService()
{
}
public event B2MML_ProcessProductionPerformance_MaterialConsumption_OBCompletedEventHandler B2MML_ProcessProductionPerformance_MaterialConsumption_OBCompleted;
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://sap.com/xi/WebService/soap1.1", OneWay=true, Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
public void B2MML_ProcessProductionPerformance_MaterialConsumption_OB(XmlDocument ProcessProductionPerformance)
{
this.Invoke("B2MML_ProcessProductionPerformance_MaterialConsumption_OB", new object[] {
ProcessProductionPerformance});
}
public System.IAsyncResult BeginB2MML_ProcessProductionPerformance_MaterialConsumption_OB(XmlDocument ProcessProductionPerformance, System.AsyncCallback callback, object asyncState)
{
return this.BeginInvoke("B2MML_ProcessProductionPerformance_MaterialConsumption_OB", new object[] {
ProcessProductionPerformance}, callback, asyncState);
}
public void EndB2MML_ProcessProductionPerformance_MaterialConsumption_OB(System.IAsyncResult asyncResult)
{
this.EndInvoke(asyncResult);
}
public void B2MML_ProcessProductionPerformance_MaterialConsumption_OBAsync(XmlDocument ProcessProductionPerformance)
{
this.B2MML_ProcessProductionPerformance_MaterialConsumption_OBAsync(ProcessProductionPerformance, null);
}
public void B2MML_ProcessProductionPerformance_MaterialConsumption_OBAsync(XmlDocument ProcessProductionPerformance, object userState)
{
if ((this.B2MML_ProcessProductionPerformance_MaterialConsumption_OBOperationCompleted == null))
{
this.B2MML_ProcessProductionPerformance_MaterialConsumption_OBOperationCompleted = new System.Threading.SendOrPostCallback(this.OnB2MML_ProcessProductionPerformance_MaterialConsumption_OBOperationCompleted);
}
this.InvokeAsync("B2MML_ProcessProductionPerformance_MaterialConsumption_OB", new object[] {
ProcessProductionPerformance}, this.B2MML_ProcessProductionPerformance_MaterialConsumption_OBOperationCompleted, userState);
}
private void OnB2MML_ProcessProductionPerformance_MaterialConsumption_OBOperationCompleted(object arg)
{
if ((this.B2MML_ProcessProductionPerformance_MaterialConsumption_OBCompleted != null))
{
System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
this.B2MML_ProcessProductionPerformance_MaterialConsumption_OBCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
}
}
public new void CancelAsync(object userState)
{
base.CancelAsync(userState);
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.17929")]
public delegate void B2MML_ProcessProductionPerformance_MaterialConsumption_OBCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs e);
Problem Decription:
I am able to send an XMLDocument successfully, however, if my XMLDocument looks like this:
<ProcessProductionPerformance xmlns="SomeNS">
<ApplicationArea>Some data here</ApplicationArea>
<DataArea>Some data there</DataArea>
</ProcessProductionPerformance>
I am seeing the below in the SOAP Body (seen via Fiddler):
<ProcessProductionPerformance>
<ProcessProductionPerformance xmlns="SomeNS">
<ApplicationArea>Some data here</ApplicationArea>
<DataArea>Some data there</DataArea>
</ProcessProductionPerformance>
</ProcessProductionPerformance>
Information:
1) I do not have access to modify the web service
2) I've tried to pack XMLDocument ApplicationArea and XMLDocument DataArea individually into a class and try to serialize the class, I end up with this in the SOAP Body:
<ProcessProductionPerformance xmlns="SomeNS">
<ApplicationArea>
<ApplicationArea xmlns="SomeNS">Some data here</ApplicationArea>
<ApplicationArea>
<DataArea>
<DataArea xmlns="SomeNS">Some data there</DataArea>
<DataArea>
</ProcessProductionPerformance>
3) I suspect it's to do with the SOAPBindingUse or SOAPBindingStyle perhaps? I did not change this at all because I don't know much about it.
4) I'm just a kid new to C#.. Please have mercy.
EDIT:
Okay it seems that the enums SoapBindingUse.Literal and SoapParameterStyle.Bare have a major role to play in this. But I'm still stuck because my use of this has been correct all along.
https://msdn.microsoft.com/en-us/library/vstudio/2b4bx2t6%28v=vs.100%29.aspx
So what am I missing?
By the way, not sure if you humans care about the client but I'm calling the service like this:
var processProductionPerformance = new XmlDocument();
processProductionPerformance.LoadXml(#xmlText);
var sendPerformanceToSap = new B2MML_ProcessProductionPerformance_MaterialConsumption_OBService
{
//Url = Link here,
//Credentials since
};
sendPerformanceToSap.B2MML_ProcessProductionPerformance_MaterialConsumption_OBAsync(processProductionPerformance);

Related

AWS SDK2 java s3 select example - how to get result bytes

I am trying to use aws sdk2 java for s3 select operations but not able to get extract the final data. Looking for an example if someone has implemented it. I got some idea from [this post][1] but not able to figure out how to get and read the full data .
Fetching specific fields from an S3 document
Basically, equivalent of v1 sdk:
``` InputStream resultInputStream = result.getPayload().getRecordsInputStream(
new SelectObjectContentEventVisitor() {
#Override
public void visit(SelectObjectContentEvent.StatsEvent event)
{
System.out.println(
"Received Stats, Bytes Scanned: " + event.getDetails().getBytesScanned()
+ " Bytes Processed: " + event.getDetails().getBytesProcessed());
}
/*
* An End Event informs that the request has finished successfully.
*/
#Override
public void visit(SelectObjectContentEvent.EndEvent event)
{
isResultComplete.set(true);
System.out.println("Received End Event. Result is complete.");
}
}
);```
///IN AWS SDK2, how do get ResultOutputStream ?
```public byte[] getQueryResults() {
logger.info("V2 query");
S3AsyncClient s3Client = null;
s3Client = S3AsyncClient.builder()
.region(Region.US_WEST_2)
.build();
String fileObjKeyName = "upload/" + filePath;
try{
logger.info("Filepath: " + fileObjKeyName);
ListObjectsV2Request listObjects = ListObjectsV2Request
.builder()
.bucket(Constants.bucketName)
.build();
......
InputSerialization inputSerialization = InputSerialization.builder().
json(JSONInput.builder().type(JSONType.LINES).build()).build()
OutputSerialization outputSerialization = null;
outputSerialization = OutputSerialization.builder().
json(JSONOutput.builder()
.build()
).build();
SelectObjectContentRequest selectObjectContentRequest = SelectObjectContentRequest.builder()
.bucket(Constants.bucketName)
.key(partFilename)
.expression(query)
.expressionType(ExpressionType.SQL)
.inputSerialization(inputSerialization)
.outputSerialization(outputSerialization)
.scanRange(ScanRange.builder().start(0L).end(Constants.limitBytes).build())
.build();
final DataHandler handler = new DataHandler();
CompletableFuture future = s3Client.selectObjectContent(selectObjectContentRequest, handler);
//hold it till we get a end event
EndEvent endEvent = (EndEvent) handler.receivedEvents.stream()
.filter(e -> e.sdkEventType() == SelectObjectContentEventStream.EventType.END)
.findFirst()
.orElse(null);```
//Now, from here how do I get the response bytes ?
///////---> ISSUE: How do I get ResultStream bytes ????
return <bytes>
}```
// handler
private static class DataHandler implements SelectObjectContentResponseHandler {
private SelectObjectContentResponse response;
private List receivedEvents = new ArrayList<>();
private Throwable exception;
#Override
public void responseReceived(SelectObjectContentResponse response) {
this.response = response;
}
#Override
public void onEventStream(SdkPublisher<SelectObjectContentEventStream> publisher) {
publisher.subscribe(receivedEvents::add);
}
#Override
public void exceptionOccurred(Throwable throwable) {
exception = throwable;
}
#Override
public void complete() {
}
} ```
[1]: https://stackoverflow.com/questions/67315601/fetching-specific-fields-from-an-s3-document
i came to your post since I was working on the same issue as to avoid V1.
After hours of searching i ended up with finding the answer at. https://github.com/aws/aws-sdk-java-v2/pull/2943/files
The answer is located at SelectObjectContentIntegrationTest.java File
services/s3/src/it/java/software/amazon/awssdk/services/SelectObjectContentIntegrationTest.java
The way to get the bytes is by using the RecordsEvent class, please note for my use case I used CSV, not sure if this would be different for a different file type.
in the complete method you have access to the receivedEvents. this is where you get the first index to get the filtered returned results and casting it to the RecordsEvent class. then this class provides the payload as bytes
#Override
public void complete() {
RecordsEvent records = (RecordsEvent) this.receivedEvents.get(0)
String result = records.payload().asUtf8String();
}

Naming Blob Dynamically for WebJob on a Schedule

I have a web job which is creating a blob based on the return value of a WebClient call. This is working fine. But as you can see from the Blob attribute (see code below), the name of the file is static. So, it is getting overwritten every time in blob storage.
Function class:
public class Functions
{
private static int _retryCount;
private static readonly int _retryLimit = int.Parse(ConfigurationManager.AppSettings["retryLimit"]);
private static readonly string _ghostRestfullUri = ConfigurationManager.AppSettings["ghostRestfullUri"];
[NoAutomaticTrigger]
public static void LightUpSite([Blob("ghost/response.json")] out string output, TextWriter logger)
{
_retryCount = 0;
output = string.Empty;
do
{
try
{
using (var request = new WebClient())
{
var response = request.DownloadString(_ghostRestfullUri);
_retryCount++;
output = response;
break;
}
}
catch(Exception exception)
{
logger.WriteLine("Job failed. Retry number:{0}", _retryCount);
}
} while (_retryCount < _retryLimit);
}
}
Main menu:
public class Program
{
static void Main()
{
var host = new JobHost();
host.Call(typeof(Functions).GetMethod("LightUpSite"));
}
}
How can I use placeholders to dynamically name the incoming file?
I have already tried the following:
ghost/{name}
ghost/{BlobName}
Other things to note:
This job is run on a schedule, so the host does not run and block
This job does not get invoked by a trigger, it just wakes up and runs;
Because the source is not coming from a message queue object or a uploaded file, I can’t figure out how I am supposed to name this blob.
Perhaps somehow using the blob storage API directly?
To name an output blob dynamically use IBinder as shown in this sample
To name an input blob dynamically as in a call from from Host.Call just pass the name of blob as argument:
static void Main()
{
var host = new JobHost();
host.Call(typeof(Functions).GetMethod("LightUpSite"), new {blobArgumentName= "container/blob"});
}

How to send additional fields to soap handler along with soapMessage?

I am logging RequestXML for a webservice client using SoapHandler as follows
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
private void logToSystemOut(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean)
smc.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
out.println("\nOutbound message:");
} else {
out.println("\nInbound message:");
}
SOAPMessage message = smc.getMessage();
try {
message.writeTo(out);
out.println("");
} catch (Exception e) {
out.println("Exception in handler: " + e);
}
}
Got a new requirenment to add this xml to DB along with some extra values(which are not present in the xml). Is there any way I can pass few additional fields to above soap handler (in handleMessage method)?
Please note that changing the xml/WSDL or adding this to SOAP message header is not an option for me as it is owned by other interface. Any other solution?
Thanks!
You can cast your service class to a class of type "BindingProvider". In this form you can use it to assign it objects which you can access later from your SOAPHandler. Another useful usage is that you also can change the endPoint URL this way.
Before calling the service you do:
MySoapServicePortType service = new MySoapService().getMySoapServicePort();
BindingProvider bp = (BindingProvider)service;
MyTransferObject t = new MyTransferObject();
bp.getRequestContext().put("myTransferObject", t);
TypeResponse response = service.doRequest();
SOAPMessage message = t.getRequestMessage(message);
From your logging function you do:
private void logToSystemOut(SOAPMessageContext smc) {
...
MyTransferObject t = (MyTransferObject) messageContext.get("myTransferObject");
if (outboundProperty.booleanValue())
t.setRequestMessage(message);
else
t.setResponseMessage(message);
...
}

TagLib-sharp: Reading metadata from HttpPostedFile object

User post their MP3s to my site and I would like to read the metadata from the files before they are stored in the CDN.
TagLib-Sharp seems to be library to go for this, but I can't see any way to open a HttPostedFile, which I don't not want to save to disk, and retrieve the metadata.
Anybody have an example on how to do this with taglib-sharp?
Edit: It seems that IFileAbstraction can solve this. Anybody know how to use IFileAbstraction?
You would want to do something as follows. The caveat is that the steam has to be seekable an I do not know if HttpPostedFile.InputStream is.
TagLib.File myFile = TagLib.File.Create(new HttpPostedFileAbstraction(postedFile));
public class HttpPostedFileAbstraction : TagLib.File.IFileAbstraction
{
private HttpPostedFile file;
public HttpPostedFileAbstraction(HttpPostedFile file)
{
this.file = file;
}
public string Name {
get { return file.FileName; }
}
public System.IO.Stream ReadStream {
get { return file.InputStream; }
}
public System.IO.Stream WriteStream {
get { throw new Exception("Cannot write to HttpPostedFile"); }
}
public void CloseStream (System.IO.Stream stream) { }
}

How do I invoke Multiple Startup Projects when running a unit tests in Debug Mode

This seems like a simple thing to do but I can't seem to find any info anywhere! I've got a solution that has a service that we run in 'Console Mode' when debugging. I want it to be started and 'attached' when I run my unit test from Visual Studio.
I'm using Resharper as the unit test runner.
Not a direct answer to your question, BUT
We faced a similar problem recently and eventually settled on a solution using AppDomain
As your solution is already running as a Console project it would be little work to make it boot in a new AppDomain. Furthermore, you could run Assertions on this project as well as part of unit testing. (if required)
Consider the following static class Sandbox which you can use to boot multiple app domains.
The Execute method requires a Type which is-a SandboxAction. (class definition also included below)
You would first extend this class and provide any bootup actions for running your console project.
public class ConsoleRunnerProjectSandbox : SandboxAction
{
protected override void OnRun()
{
Bootstrapper.Start(); //this code will be run on the newly create app domain
}
}
Now to get your app domain running you simply call
Sandbox.Execute<ConsoleRunnerProjectSandbox>("AppDomainName", configFile)
Note you can pass this call a config file so you can bootup your project in the same fashion as if you were running it via the console
Any more questions please ask.
public static class Sandbox
{
private static readonly List<Tuple<AppDomain, SandboxAction>> _sandboxes = new List<Tuple<AppDomain, SandboxAction>>();
public static T Execute<T>(string friendlyName, string configFile, params object[] args)
where T : SandboxAction
{
Trace.WriteLine(string.Format("Sandboxing {0}: {1}", typeof (T).Name, configFile));
AppDomain sandbox = CreateDomain(friendlyName, configFile);
var objectHandle = sandbox.CreateInstance(typeof(T).Assembly.FullName, typeof(T).FullName, true, BindingFlags.Default, null, args, null, null, null);
T sandBoxAction = objectHandle.Unwrap() as T;
sandBoxAction.Run();
Tuple<AppDomain, SandboxAction> box = new Tuple<AppDomain, SandboxAction>(sandbox, sandBoxAction);
_sandboxes.Add(box);
return sandBoxAction;
}
private static AppDomain CreateDomain(string name, string customConfigFile)
{
FileInfo info = customConfigFile != null ? new FileInfo(customConfigFile) : null;
if (!string.IsNullOrEmpty(customConfigFile) && !info.Exists)
throw new ArgumentException("customConfigFile not found using " + customConfigFile + " at " + info.FullName);
var appsetup = new AppDomainSetup();
//appsetup.ApplicationBase = Path.GetDirectoryName(typeof(Sandbox).Assembly.Location);
appsetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
if (customConfigFile==null)
customConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
appsetup.ConfigurationFile = customConfigFile;
var sandbox = AppDomain.CreateDomain(
name,
AppDomain.CurrentDomain.Evidence,
appsetup);
return sandbox;
}
public static void DestroyAppDomainForSandbox(SandboxAction action)
{
foreach(var tuple in _sandboxes)
{
if(tuple.Second == action)
{
AppDomain.Unload(tuple.First);
Console.WriteLine("Unloaded sandbox ");
_sandboxes.Remove(tuple);
return;
}
}
}
}
[Serializable]
public abstract class SandboxAction : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null;
}
public void Run()
{
string name = AppDomain.CurrentDomain.FriendlyName;
Log.Info("Executing {0} in AppDomain:{1} thread:{2}", name, AppDomain.CurrentDomain.Id, Thread.CurrentThread.ManagedThreadId);
try
{
OnRun();
}
catch (Exception ex)
{
Log.Error(ex, "Exception in app domain {0}", name);
throw;
}
}
protected abstract void OnRun();
public virtual void Stop()
{
}
}