I'm providing a WCF service in my .net core project via SoapCore. In one of the methods, I want to access the SOAP envelope header info. To test that, I've added the following code:
[ServiceContract]
public interface IDataService {
[OperationContract]
string TransmitObject(XElement node);
}
// -------------------------------------------------------------------------
public string TransmitObject(XElement node) {
foreach(var header in OperationContext.Current.IncomingMessageHeaders) {
Console.WriteLine(header.ToString());
}
return JsonConvert.SerializeXNode(node, Formatting.None);
}
However, in this case, the OperationContext.Current attribute is always null. What do I need to change in order to make that work?
Related
I have a very strange and obscure issue with WCF services that I was hoping to get some insight on:
I am working a WCF service that we are building to replace one that we no longer have source code for. For some reason, in the new WCF service, everything is forced through a single paramater called "request". Using the WCF test client, this is what it looks like
On the "correct" service, this is what it looks like:
Is there any reason why this would be happening? I've defined all of the requests as follows:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string SomeRequest();
}
Which seems correct, but there may be something I've overlooked that is causing this.
In your original WCF service, there is a request function parameter, and it has a definition similar to the following:
[ServiceContract]
public interface IMyService
{
[OperationContract]
Request SomeRequest(Request request);
}
[DataContract]
public class Request
{
string documentId;
[DataMember]
public string DocumentId
{
get { return documentId; }
set { documentId = value; }
}
}
In the new wcf service:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string SomeRequest(string documentId);
}
So this is because the function parameters are different. Originally your parameter was class, but later changed to string, so the display in WCFTestClient is different.
First of all, I want to share my scenario what i want to build -
Scenario:
I am building a client app using wpf. In some cases, I need to call a web service to get data from the server. In order to do this, I added a web reference using wsld url. And I created a ServiceManager class that will call service method. For security reason, I need to add some header info at soap xml request for example, UserToken, SAML Token and so on. I can this from my ServiceManager class. But I want to add another class which will be called before sending request to the server. In that class, I will do something like adding security header to soap xml request with request and then send it to the server.
I used SOAP Extension to fulfill my purpose and it works well. But the problem is, every-time I need to add annotation in Reference.cs (for each web service reference) file at top of the service method. I believe that there is some other easiest way to make this working better than SOAP Extension. Is there any way where I can only call the service and a delegate class will be called automatically and I don't need to add any annotation to the reference file? I will share my sample code here.
ServiceManage class:
public class ServiceManager
{
public UserDataService dataService; //web service added at Web Reference
public ServiceManager()
{
dataService = new UserDataService();
getUserServiceRequest rqst = new getUserServiceRequest();
getUserServiceResponse resp = dataService.getUser(rqst);
}
}
Reference.cs
[TraceExtensionAttribute(Name = "First")]
public getUserServiceResponse getUser([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] getUserServiceRequest request) {
object[] results = this.Invoke("getUser", new object[] {
request});
return ((getUserServiceResponse)(results[0]));
}
TraceExtensionAttribute.cs
[AttributeUsage(AttributeTargets.Method)]
public class TraceExtensionAttribute : SoapExtensionAttribute
{
private string mstrName = null;
public override Type ExtensionType
{
get { return typeof(TraceExtension); }
}
public override int Priority
{
get { return 1; }
set { }
}
public string Name
{
get { return mstrName; }
set { mstrName = value; }
}
}
TraceExtension.cs
public class TraceExtension : SoapExtension
{
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attr){//..do something}
public override void Initialize(object initializer){//..do something}
public override Stream ChainStream(Stream stream){//...do something}
public override void ProcessMessage(SoapMessage message) {//..do something}
}
Finally, I found the solution. Just through out Web Reference and add Service Reference instead. Then go to the following link. It works for me.
I have this GREAT WCF service that returns Data from EF.
public class HistoryDataService : DataService<HistoryEntities>
{
#region Public Methods
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
[WebGet]
public IQueryable<History> GetHistoriesById(int recordId)
{
return CurrentDataSource.Histories.Where(d => d.RecordId == recordId);
}
#endregion
}
I have other services that I added something like:
[WebGet(UriTemplate = "eventdetails/{id}", ResponseFormat = WebMessageFormat.Json)]
to make it more of a traditional RESTful service, however, when I add it I get various errors like:
... both defines a ServiceContract and inherits a ServiceContract from type System.Data.Services.IRequestHandler.`
How do I add this property or is it even possible?
It would save you a lot of time to use WCF Data Services or OData as it is called. You'll get both JSON and XML output for your web service response. Your choice. : )
WCF Data Services
I have a wcf application in which i have used Entitity Framework and have implemented dbContext for querying the database.
When I view the svc file in browser it exposes the operations.
I have interface class like this:
[ServiceContract]
public interface IService1
{
[OperationContract]
List<BooksModels> GetBooksList();
[OperationContract]
BooksModels GetBook(int id);
}
I have the implementation in the svc.cs file like this
public List<BooksModels> GetBooksList()
{
MVCEntity en = new MVCEntity();
return en.book.ToList();
}
public int GetBookId(int id)
{
//return db.book.Find(id);
return 1;
}
and the BooksModels class is like this
[DataContract]
public class BooksModels
{
[Key]
[DataMember]
public int BookId { get; set; }
[DataMember]
public string BookName{get;set;}
}
and have the config file the default one as created when creating wcf service application .
but when i invoke GetBooksList the service from MVC wcf client it gives me the following error:
Failed to invoke the service. Possible causes: The service is offline
or inaccessible; the client-side configuration does not match the
proxy; the existing proxy is invalid. Refer to the stack trace for
more detail. You can try to recover by starting a new proxy, restoring
to default configuration, or refreshing the service.
but when i invoke the second method that returns 1.
i examined that when the service uses the dbContext to return data it gives error and
is fine when not.
I have gone through various blogs and also the questions in stackoverflow but didn't help.
so how can this problem be addressed.
Thanks
I think it's a problem of serialization. Make a serialisation test from you're business layer that take List from entity framework and serialize then deserialize it and compare before and after serialization.
Use DataContractSerializer :
DataContractSerializer serialiser = new DataContractSerializer(typeof(List<BooksModels>));
List<BooksModels> expected = business.GetBooksList();
Stream stream = new MemoryStream();
serialiser.WriteObject(stream, expected);
stream.Position = 0;
List<BooksModels> actual = serialiser.ReadObject(stream) as List<BooksModels>;
Assert.IsNotNull(actual);
Assert.AreEqual(expected.Prop1, actual.Prop1);
Assert.AreEqual(expected.Prop2, actual.Prop2);
// ... //
If it doesn't work you probably use proxy in entity framework. turn off proxy :
context.ContextOptions.ProxyCreationEnabled = false;
I had the same problem. Thanks to Brice2Paris, I solved it by turning off the proxy of EF:
context.Configuration.ProxyCreationEnabled = false;
I try set soap extension attributes on client side. For example:
Implementation in web service:
[AttributeUsage(AttributeTargets.Method)]
public class EncryptMessageAttribute : SoapExtensionAttribute
{
private string strKey="null";
public string StrKey
{
get { return strKey; }
set { strKey = value; }
}
}
Soap extension class:
public class EncryptMessage : SoapExtension
{
...
}
Used on web method:
[WebMethod]
[EncryptMessage( StrKey = "pass")]
public string test2()
{
return "ok";
}
Implementation in Proxy class:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/test", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[EncryptMessage( StrKey = "pass")]
public string test() {
object[] results = this.Invoke("test", new object[0]);
return ((string)(results[0]));
}
Soap extension attributes are::[EncryptMessage( StrKey = "pass")]
I want to set Soap Extension Attribute on client side, before than I use Soap Extension, when I call some web methods.
Example: I call some method, wich set soap extension attributes on both side, before than soap extension is used. Can somebody help me ?
First of all, if you can use WCF for this, then you should. Microsoft has stated that ASMX web services are "legacy technology", and that all new web service development should use WCF.
In any case, see the SoapExtensionReflector and SoapExtensionImporter classes. Note that these will only work for .NET, ASMX clients.