I have been tasked with writing a web-service that will be used as an integration point between an ASP.NET MVC application and corporate SAP. Basically, I just have to write a SOAP web-service (Wcf SOAP) with an endpoint that SAP will call and transmit a bunch of data that I will then have to store in a SQL Server database.
I've never written a web-service before and am a but unsure on how the process will ultimately work. I generated an XML schema from the EF classes in the MVC application which I plan to provision SAP with for the data they are to send to the web-service. My solution designer suggested that I mimic the message structure that he uses in one of his REST web-services. This structure is as follows for the in-comming request:
public class DtoRequest<T> : IDtoRequest where T : class
{
public InteractionContext Context { get; set; }
public T Request { get; set; }
}
The InteractionContext is to hold various properties such details of the calling application and a license key for authentication. The Request will contain the payload.
namespace RfqService.Messages
{
public class SendRfqRequest : DtoRequest<RequestDataDto>
{
}
public class SendRfqResponse : DtoResponse<DtoVoidResponse>
{
}
}
The RequestDataDto looks as follows:
namespace RfqService.DataTransferObjects
{
[DataContract]
public class RequestDataDto
{
[DataMember]
public int RequestId { get; set; }
[DataMember]
public DateTime CreatedDate { get; set; }
[DataMember]
public DateTime DateProcessed { get; set; }
[DataMember]
public string Status { get; set; }
[DataMember]
public string XmlData { get; set; }
}
}
What I'm planning is for the XmlData in the RequestDataDto to contain the xml data sent from SAP that I can then deserialize into the EF classes and persist to the database.
SAP can then call an endpoint in my .asmx file:
[WebMethod]
public SendRfqResponse SendRfq(SendRfqRequest request)
{ ... }
Problem I'm facing is when inspecting the implementation of the the REST service of the solution designer. He calls the REST endpoint from a Webforms application. I can see how he constructs the message object in C# and send it to the web-service. I have no idea how this will work when its coming from a different platform like SAP. I've been trying to read up on SOAP in general and have come across the following extract here:
The primary difference between ORPC and the RPC protocols that preceded them was that ORPC codified the mapping of a communication endpoint to a language-level object.
Is the data sent from SAP automatically converted to my Request object? Does the data come in XML and I have to deserialize it into my object that in turn contains xml data in the payload? Are the parameters in the InteractionContext come from what's in the SOAP object's header? Do I have to serialize my response into xml before returning it to SAP?
Example If you are doing a REST web service call
If you really are doing a SOAP call.
Then load create a new client service using the wsdl from IIS where the service is hosted.
This will create a PROXY in ABAP.
You just call that proxy.
The data sent is transformed in XML as per the WSDL definition for you.
Equally on the IIS end the Service should populate the your Data Contract type for you automatically.
You should not have to worry about XML anywhere if done properly and you are using SOAP.
ABAP->IIS
if its aysnch call you will need to set up reliable messaging on the SAP side. That will keep you basis guy busy
Related
I am currently trying to develop a SCIM endpoint to be called from AAD. I pretty much understand the setup of SCIM and the idea behind it (I think). The problem is that I can't wrap my head around how to practically work with the Schemas. Should I make a model in C# that reflects the Schema that we end up using or should I try to do some clever logic that "looks up" the schema in the endpoint when a AAD for instance tries to create a user and then parse the JSON based on that or is there another approach that I am totally missing?
I am using a .NET Core Web API and have a Users controller so far as I do not really need anything else for now from AAD.
Any help with how to "use" these schemas in practice will be greatly appreciated!
This sample may be helpful - https://github.com/AzureAD/SCIMReferenceCode/blob/master/Microsoft.SystemForCrossDomainIdentityManagement/Schemas/Core2UserBase.cs
namespace Microsoft.SCIM
{
using System.Collections.Generic;
using System.Runtime.Serialization;
[DataContract]
public abstract class GroupBase : Resource
{
[DataMember(Name = AttributeNames.DisplayName)]
public virtual string DisplayName
{
get;
set;
}
[DataMember(Name = AttributeNames.Members, IsRequired = false, EmitDefaultValue = false)]
public virtual IEnumerable<Member> Members
{
get;
set;
}
}
When configuring your app in AAD you will also be able to go into the app > provisioning > attribute mappings > show advanced options > and then specify which attributes are required
I would like to write method validation processes which will be similar to data annontations presented in Web API.
In web api we can validate an object, for example:
public class Numbers
{
[NumberOne]
public string Number1 { get; set; }
[NumberTwo]
public string Number2 { get; set; }
}
and as long as we define the attributes NumberOneAttribute and NumberTwoAttribute its gonna be ok.
The difference is that web api has access to the GlobalConfiguration.Configuration.Filters which it seems like signalr doesn't.
Is there anyway to validate requests by attributes? or I need to follow the worst case, validate each input in the invoked method?
Thanks,
Ori.
In SignalR 2.2.x there is no native way of achieving this, but there is a project on GitHub that that adds a Validation Module in the SignalR pipeline.
Basically, in order to use it, you add a new module to the pipeline:
GlobalHost.HubPipeline.AddModule(new ValidationModule());
Then, you can use attributes like [Required] for the models' properties and then decorate the desired methods with the [Validate] attribute.
Note that this is a proof of contept project.
Best regards!
A long time ago when I first looked at OData response payloads to GET requests contained links to other entities or entity sets (e.g. an OrderHeader entity would contain a link to the order's OrderDetails). I believe the correct term for this is hypermedia.
Today I'm checking out OData again and have built a OData v4 service using ASP.Net Web API however no such hypermedia links are being returned in the payloads. Why is this? Is it because the payload is now JSON (whereas when I looked years ago it was XML)? Is there any way to include hypermedia links in the payload?
Here's what I've built. I have an entity called Proposition:
public class Proposition
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Event> Events { get; set; }
}
Notice that a Proposition has a collection of Events. I was hoping that when I requested a Proposition via the OData endpoint that I would get a link to the Events resource, but I don't:
I've found some information at OData JSON Format Version 4.0 Plus Errata 02#JSON Format Design that suggests adding $format=odata.metadata=full to the URL will return what I need:
The odata.metadata=full format parameter indicates that the service MUST include all control information explicitly in the payload
(odata.metadata=full)
but I've tried that and I'm not getting back any such metadata (screenshot this time from Postman):
Postman shows me that what got returned was odata.metadata.minimal:
Why is it ignoring my request for full metadata?
You should be able to add $format=application/json;odata.metadata=full to your querystring to achieve this via a GET request.
Aha, nailed it. I was specifying the URL wrongly. It needs to be ?$format=application/json;odata.metadata=full
Thanks to Stuart Preston for the help: https://twitter.com/StuartPreston/status/601107122550616064
I built a WCF service and there's a section that looks like this:
[ServiceContract]
public class Service {
[OperationContract]
public SomethingElse[] Method(Code a, params Something[] b) { ... }
}
[DataContract]
public class Something {
[DataMember]
public string Stuff {get;set;}
[DataMember]
public Status MyStatus {get;set;}
public string ServerSideField {get;set;}
}
[DataContract]
public class SomethingElse {
[DataMember]
public Status MyStatus {get;set;}
}
[DataContract]
public enum Status {
[EnumMember] WorksFine,
[EnumMember] NotWorking
}
[DataContract]
public enum Code {
[EnumMember] TypeA,
[EnumMember] TypeB
}
Now I am using it as a service reference for a C# client. For some reason, whenever I call Method, the MyStatus property inside the b parameter is always set to WorksFine, even if I set it to NotWorking. On the other hand, whenever I pass Code.TypeA or Code.TypeB for the a argument, the service always deserializes it correctly.
For the sake of due diligence, other posts on the subject of passing enums to WCF services refer to DataContract, EnumMember(Value="TypeA"), and ServiceKnownType so I gave all of those a shot. However, even when I use ServiceKnownType (like below), I am still encountering the same problem.
[ServiceContract]
[ServiceKnownType(typeof(Something)]
[ServiceKnownType(typeof(Status)]
public class Service {
[OperationContract]
public SomethingElse[] Method(Code a, params Something[] b) { ... }
}
This issue seems unusually obscure for something so basic. I tested passing back Status.NotWorking from the service as well and the client is able to see it, so this appears to be a one-way issue. Any suggestions?
EDIT 1:
Similar issue: WCF not deserializing value types. Mysterious behaviour
EDIT 2:
Judging from the lack of immediate response, I am going to include some more information in case some of it sticks.
I'm experiencing this problem on both .NET 4.5 and 4.0.
The service is hosted on IIS, has SSL, and custom authentication scheme.
There is also a FaultContract attribute on Method but I excluded it to make the example simpler.
Event Viewer says zilch. So does IIS logs.
Auto-generated service reference code in Reference.cs looks like this:
The enum:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.datacontract.org/2004/07/Service")]
public enum Status{ TypeA, TypeB }
The method:
// CODEGEN: Parameter 'MethodResult' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlArrayAttribute'.
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/Service/Method", ReplyAction="http://tempuri.org/Service/MethodResponse")]
[System.ServiceModel.FaultContractAttribute(typeof(MyClientProject.Service.MyFault), Action="http://tempuri.org/Service/MethodMyFaultFault", Name="MyFault", Namespace="http://schemas.datacontract.org/2004/07/Service.MyFault")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
MyClientProject.Service.Method Method(MyClientProject.Service.MethodRequest request);
EDIT 3:
I built another web service consisting of just the code above, but it does NOT reproduce the behavior that I am seeing. My conjecture is that either some other code is zilching the DataContractSerializer, OR there is some relevant IIS/WCF setting, OR some unresolved data contract issues.
I also built another web client that connects to both webservices, and it is receiving the same results as the first.
EDIT 4
Intercepted request with Fiddler and it looked like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Method xmlns="http://tempuri.org/">
<a>TypeA</a>
<b><Something xmlns="http://schemas.datacontract.org/2004/07/TestService.Something">
<Stuff>mystuffvalue</Stuff>
</Something></b>
</Method>
</s:Body>
</s:Envelope>
So the enum is never being passed after all! How do I fix this contract mismatch?
EDIT 5
Forgot to mention that the web service had a reference to an ASMX service and was itself using XML serializer to communicate with that external service.
The key is here:
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
The XML Serializer is being used to generate the proxy instead of the DataContractSerializer. Did you accidentally specify the XmlSerializer? Are you trying to use an .asmx service?
Once you figure out what is causing the code to be generated using the XmlSerializer you'll have your answer, but it's not immediately evident from what you have posted.
For some unknown reason, the SOAP request made by the client was omitting the enum values that I needed, and consequently the server serialized those enums to their default values (the first enum definition on the list).
I fixed this issue by making omitted parameters required for the request body. This is the code that fixed it:
[DataContract]
public class Something {
[DataMember]
public string Stuff {get;set;}
[DataMember(IsRequired=true)] // just this 1 simple change!
public Status MyStatus {get;set;}
public string ServerSideField {get;set;}
}
I have a working Web API that i am converting to a .Net Azure Mobile Service. The API returns a complex model - objects with properties - some of which are collections of other objects. This works as expected with plain Web API but with Azure Mobile Services I have an issue where one of my models does not have all it's properties serialized.
When i set a break point on the return statement in the controller, I see that all the properties and their values are present. This leads me to believe that the issue is with serialization (JSON).
return Request.CreateResponse(HttpStatusCode.OK, myModel);
Examples of properties that are being serialized:
public Guid Id { get; set; }
public IEntityDto ModelDto { get; set; } //this is an object with many properties all of which serialize
Examples of properties that are NOT being serialized:
public ItemStatus Status { get; set; } //this is an enum
public string Message { get; set; }
public string TestProp { get; set; } //this is a simple string property I added to help debug
How can I go about further debugging this so that i can see why these properties are being excluded?
Note: At the moment I am still running this locally not off Azure. This is with Visual Studio 2013 Update 2 RTM.
UPDATE: Upon closer inspection it appears that the properties not being serialized are properties that are either enums or have a value of null.
As #carlosfigueira mentioned in a comment to the original question, the default behavior of the JSON serializer is to exclude properties with null and default values. To address this I changed the following settings:
httpConfig.Formatters.JsonFormatter.SerializerSettings.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Include;
httpConfig.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;
...where httpConfig is of type HttpConfiguration. You can make these changes on app start - in a config file like WebApiConfig.cs or directly in Global.asax.cs.