I have a WCF service code like this:
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class SomeService
{
public string Password { [OperationContract] get; [OperationContract] set; }
public void CheckPassword()
{
if (Password == null || Password != "password")
throw new FaultException("Invalid Password");
}
[OperationContract]
public string SomeMethod()
{
this.CheckPassword();
return "Some Data";
}
}
And the client windows application consumes it like this:
public class ClientClass
{
public ClientClass()
{
STASomeService.Value.SomeMethod();
}
}
public class ClientClass
{
public ClientClass()
{
STASomeService.Value.set_Password("password");
}
}
How can I reset the value of SomeService.Password whenever the SomeService class is instantiated? I do not want an attacker to access my service methods, but when the actual client set the password, the passwords stays in the SomeService.Password property in every service call. But I want to retain the Password value per instance because the client needs that.
My code is in C#, framework 4, build in VS2010 Pro.
Please help. Thanks in advance.
You shouldn't have to reset the value of SomeService.Password because it isn't static. Are you seeing something to the contrary?
Since you're using InstanceContextMode.Single (which I originally overlooked), your best recourse my be to mock the behavior of having individual instances in your network bound singleton. The only way I can think of to facilitate this is to have a proxy service class that matches your service's contracts and delegates its calls to custom instances based on specific criteria (which would define the session). It would be cumbersome to maintain this way and adds a unnecessary level of abstraction, but (in my head at least) it should work
Related
I have a clean architecture project that provide micro services, one of which is to access Agresso ERP web services.
https://***************/service.svc
it provide many services
https://**/service.svc?FooService/Foo
https://**/service.svc?BooService/Boo
each of which has it's own service reference(connected service), and each of which has many methods.
each call to any of the end point you need to pass credentials with it.
var fooSoapClient = new FooSoapClient();
var credentials = new WSCredentials
{
Username = "fakeuser",
Password = "fakepassword",
Client = "fakeclient",
};
var result = fooSoapClient.GetFoosAsync(Foo filter,true,
credentials );
(P.S) credential class exist in all entities
namespace Foo1NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
namespace Foo2NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
i can access all end points with no problem.
I have the following Questions:
Is there a generic solution i can follow for not to Fall in DRY?
is there a design pattern that best target this issue?
Here is what I've done in the past, it fits in well into Dependency Injection/containers if you use that as well. The key thing here is to define an single interface that all services will implement. Your code that uses this should only be using the interface.
Each class should implement an interface you define, e.g. IWebServiceOperations
public interface IWebServiceOperations
{
WebServiceOperationResult GetFooAsync(WebServiceOperationRequest request);
}
I'll leave you to figure out the classes WebServiceOperationResult/Request, they just hold your request/response variables, including credentials.
Then each webservice you need to implement is done in a separate class. You also dictate in the constructor what type of implementation this is (FooSoap1 vs FooSoap2) e.g.
public class FooSoapClient : BaseClient, IWebServiceOperations
{
public FooSoapClient() : base(Clients.FooSoap1)
public GetFooAsync(...)
{
...
}
}
public class BaseClient
{
private readonly eFooServiceType _serviceType;
public eFooServiceType ServiceType {
get{
return _serviceType;
}
}
protected BaseClient(eFooServiceType service)
{
_serviceType = service;
}
}
Now you should have a bunch of class references. Either your DI container can resolve these for you, based on the service type you want, or you could add them to a Dictionary, so if you wanted to operate against FooSoap1, you'd do...
var fooSoapClient1 = myServices[Clients.FooSoap1];
await fooSoapClient1.GetFooAsync(...)
I have a WCF Service with the following operation contract:
[OperationContract]
Response SearchEntities(Query query);
This operation takes a request that contains a specified Entity like so:
[DataContract]
public class Query
{
[DataMember]
public string SearchTerm { get; set; }
[DataMember]
public string Entity { get; set; }
[DataMember]
public bool ExactMatch { get; set; }
}
Based on the value contained within the Entity property, one the following properties is populated within this response:
[DataContract]
public class Response
{
[DataMember]
public List<Asset> Assets { get; set; }
[DataMember]
public List<Stage> Stages { get; set; }
[DataMember]
public List<Sector> Sectors { get; set; }
}
Terrible design, I know! However. I am using Autofac.Wcf as my service factory to inject dependencies. Normally I would use a common Interface and Generics to determine a service to use based on the Entity value like so:
public interface IEntitySearch<T>
{
Response Search(Query query);
}
The above interface would have several implementations for each of the Lists within the response. Using a design pattern such as a service location I could determine which service to use (all of which inherit from IEntitySearch<T>, something like:
public IEntitySearch ResolveSearcher(Query query)
{
switch(query.Entity)
{
case "Assets":
return _container.Resolve<AssetSearch>();
case "Stages":
return _container.Resolve<StageSearch>();
default:
throw new NotSupportedException();
}
}
While this works, a more elegant solution (I believe) would be to customize the Autofac container per request for this particular operation, depending on the data contained within the request.
IE: Before the WCF pipe line sends the request to the service implementation, is it possible to examine the request data and customize how the container resolves dependencies. That way I can avoid exposing dependency resolution within my service layer.
Is this possible?
If another DI library other than Autofac has a solution for this, I will happily change our DI framework.
Thanks.
I haven't personally tried this but I think a direction you can go down is to combine:
Using OperationContext.Current to get the current request message data.
Specifying a custom IServiceImplementationDataProvider for Autofac that tells Autofac which WCF interface to host for that request.
Using a lambda registration for your service implementation to switch the backing service based on OperationContext.Current.
You can see two examples of the IServiceImplementationDataProvider by looking at the DefaultServiceImplementationProvider - the one that works in Autofac WCF hosting by default; andMultitenantServiceImplementationDataProvider, which is more about generating a proxy to enable multitenant WCF hosting.
While neither of these use OperationContext.Current to determine the actual backing service, you can build on the ideas:
Look at the Autofac.Multitenant.Wcf implementation. You may be able to use it as-is. The point of the instance data provider there is that WCF grabs on to the concrete type of the service being hosted and if you try to swap types out from under it, you get errors. The multitenant support fools WCF by creating a proxy type and your implementation type can be swapped out under the proxy. Note the MultitenantServiceImplementationDataProvider doesn't actually tie anything to a tenant or tenant ID; it's only about that proxy.
In your .svc file specify a service interface rather than any individual concrete implementation since you'll be swapping out the implementation.
Use a lambda registration to figure out your implementation.
Make sure your service is InstanceContextMode.PerCall to ensure things get swapped out on a per request basis.
The registration might look something like this:
builder.Register(ctx => {
var context = OperationContext.Current;
var type = DetermineTypeFromContext(context);
return ctx.Resolve(type);
}).As<IMyServiceInterface>();
The Autofac WCF and Autofac Multitenant section on WCF may also help.
In my opinion you're trying to move your problem just to another place. Why would making decision based on request at low-level WCF is better than switch in SearchEntities method? It's much worse ;-)
I would consider to use IEntitySearch factory/provider e.q.IEntitySearchProvider (it's not so much better but always).
public interface IEntitySearch
{
bool IsMatchQuery(Query query);
Response Search(Query query);
}
// without service locator
public class EntitySearchProvider : IEntitySearchProvider
{
private readonly IEnumerable<IEntitySearch> _searchers;
public EntitySearchProvider(IEnumerable<IEntitySearch> searchers)
{
_searchers = searchers;
}
public IEntitySearch GetSearcher(Query query)
{
// last registered
return _searchers.LastOrDefault(i=>i.IsMatchQuery(query))
?? throw new NotSupportedException();
}
}
or
public interface IEntitySearchProvider
{
IEntitySearch GetSearcher(Query query);
}
public class EntitySearchProvider : IEntitySearchProvider
{
private readonly IComponentContext _container;
public EntitySearchProvider(IComponentContext container)
{
_container = container;
}
public IEntitySearch GetSearcher(Query query)
{
switch(query.Entity)
{
case "Assets":
return _container.Resolve<AssetSearch>();
case "Stages":
return _container.Resolve<StageSearch>();
default:
throw new NotSupportedException();
}
}
}
with
public class WcfService
{
private readonly IEntitySearchProvider _provider;
public WcfService(IEntitySearchProvider provider)
{
_provider = provider;
}
public Response SearchEntities(Query query)
{
var searcher = _provider.GetSearcher(query);
return searcher.Search(query);
}
}
I’ve created an object that I would like to pass in a WCF call… but inside ServiceReference1… this object is redefined… is there a way to just use the original object everywhere… it seems like people have done this but I can’t figure out what I am doing wrong.
The object is used as a parameter to a function in the service contract.
[OperationContract(IsOneWay = true)]
void UpdateInformation(MyObject myObject);
The error that I get when I try to call the function from my client is “Argument 1: cannot convert from ‘MyNameSpaceDTO.MyObject' to ‘MyNameSpace.ServiceReference1.MyObject’”
The object is in it’s own class library dll and it is marked with [DataObject] and [DataMember] attributes.
namespace MyNameSpaceDTO
{
[DataContract]
public class MyObject
{
[DataMember]
public string Name { get; set; }
….
But, also ends up in Reference.cs after adding the Service Reference as:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="MyObject", Namespace="http://schemas.datacontract.org/2004/07/MyNameSpaceDTO")]
[System.SerializableAttribute()]
public partial class MyObject : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string NameField;
...
Also, I do have the following set in the Advanced section of the Add Service Reference:
[x] Reuse types in referenced assemblies
(o) Reuse types in all referenced assemblies
For consuming a WCF service you often see samples (and they're undoubtedly advisable!) where you're instructed to add that service via the Add Service Reference dialog. By referencing a service that way your client application creates proxy classes form the WSDL exposed by the service.
As a result you end up having e.g. a class MyNameSpaceDTO.MyObject in your contract-assembly and a MyNameSpace.ServiceReference1.MyObject in your client application which was generated form the WSDL. This may seem somewhat redundant.
One situation in which you may need this behaviour could be the following: Imagine you'd want to consume an arbitrary public web service which you don't control. You have no access to the contract-assembly which defines the types etc. In that situation creating your own local proxy classes from the exposed WSDL is optimal since it's your only way to get the needed types and so on.
But your concrete situation seems to be a little bit different. I think what you're looking for is a shared contract. Since you're in control of the client and server code (and both live happily side by side in the same solution), you're in the comfortable situation to just share the contract:
So instead of adding a service reference within your client-app (via Add Service Reference), you'd just reference the contract-assembly (via the usual Add Reference dialogue). By doing this there'll by only one MyNameSpaceDTO.MyObject since the second one is never created and not needed. This approach is called contract sharing.
Please take a look at that example:
EDIT:
Please note some changes: The most important one is that you usually wouldn't want to share the assembly which holds your implementation logic of your service. So I extracted that part from the Contract-assembly and put it in a separate Implementation-assembly. By doing so, you simply share the interfaces and types and not the implementation logic. This change is reflected in the screenshot above, too.
You could set up that small solution with the following classes:
Contract - IService1.cs:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
Implementation - Service1.cs:
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
Host - Program.cs:
class Program
{
static void Main(string[] args)
{
var baseAddress = new Uri("http://localhost:8732/Design_Time_Addresses/Service1/");
using (var host = new ServiceHost(typeof(Service1), baseAddress))
{
// Enable metadata publishing.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since no endpoints are
// explicitly configured, the runtime will create one endpoint per base address
// for each service contract implemented by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
host.Close();
}
}
}
Client - Program.cs:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press <Enter> to proceed.");
Console.ReadLine();
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress("http://localhost:8732/Design_Time_Addresses/Service1/");
var channelFactory = new ChannelFactory<IService1>(binding, endpoint);
// Create a channel.
IService1 wcfClient1 = channelFactory.CreateChannel();
string s = wcfClient1.GetData(42);
Console.WriteLine(s);
((IClientChannel)wcfClient1).Close();
Console.WriteLine("Press <Enter> to quit the client.");
Console.ReadLine();
}
}
I am starting out with WCF. I have created two console apps (server and client) that work without any issues but since moving them onto forms I'm having all kinds of problems. I had a look here and elsewhere on the net, I can't seem to find anything that can help me with my issue. I honestly don't understand the issue but I think it may have something to do with my datatypes (they're under different namespaces)?
Here's my Server code:
public partial class Form1 : Form
{
ModelDataServer Server;
public ScraperForm()
{
InitializeComponent();
Server = new ModelDataServer(); // Opened Here
Server.Scraper = this;
}
}
[ServiceContract]
public interface IModelData
{
[OperationContract]
ArrayList GetData();
}
[ServiceBehavior(UseSynchronizationContext=false)]
public class ModelDataServer : IModelData
{
ServiceHost Host;
public DataModel Model { private get; set; }
public ModelDataServer()
{
Host = new ServiceHost(typeof (ModelDataServer),
new Uri[]
{
new Uri("http://localhost:8000")
});
Host.AddServiceEndpoint(typeof(IModelData),
new BasicHttpBinding(),
"ModelData");
Host.Open(); // Error Points Here!!!
}
public ArrayList GetData()
{
return Model.GetData();
}
public void CloseServer()
{
Host.Close();
}
}
Here's my Client code:
[ServiceContract]
public interface IModelData
{
[OperationContract]
ArrayList GetData();
}
[ServiceBehavior(UseSynchronizationContext = false)]
public class ModelDataClient
{
ChannelFactory<IModelData> HttpFactory;
IModelData HttpProxy;
public ModelDataClient()
{
HttpFactory = new ChannelFactory<IModelData>(
new BasicHttpBinding(),
new EndpointAddress("http://localhost:8000/ModelData"));
HttpProxy = HttpFactory.CreateChannel();
}
public ArrayList GetData()
{
return HttpProxy.GetData();
}
}
Here's the error I'm recieving (points to where I'm opening the ServiceHost):
The ChannelDispatcher at 'http://localhost:8000/ModelData' with contract(s) '"IModelData"' is unable to open its IChannelListener.
P.S. I have been struggling to get delegates to work outside of something I've done in a tutorial. If anyone can suggest a better way that uses delegates instead of passing my form class into the other class that would be great.
Yes, this is most likely related to namespace issues. For illustration issues, let's assume your server project's namespace is ServerApp, and your client's namespace is ClientApp. You define IModelData in both applications, which means you have ServerApp.IModelData and ClientApp.IModelData. Even though the code is identical, these are two separate interfaces (because of the namespace).
So you're trying to pass ClientApp.IModelData to the service, and it's expecting ServerApp.IModelData.
You can solve this by moving the interface IModelData to its own assembly and having the server app and the client app both reference this third assembly. That's what we do at work - all of our service contracts are in a separate assembly (two, actually, but that's a different story).
A couple of other things to note:
Unless your client is also hosting a service, you can remove the [ServiceContract] attribute from the class. Clients don't need that.
In your server app, what is Server.Scraper = this; for? It appears to be assigning the Form to a property Scraper in the service, but I don't see that property in your code. Additionally, services don't really use properties (I think I saw somewhere that you could do it, but it wasn't intuitive). I don't think you'd want to assign the entire form to the service, as service's in and of themselves don't usually have UIs - they supply data and receive data from the service.
I am using VSTS 2008 + .Net + C# 3.5 to develop WCF service (self-hosted as a Windows Service). From client side, I am using ChannelFactory to connect to WCF service. My confusion is, when I change client side code from "public string response" to "public string responseAliasName", the value of responseAliasName is null. But when change back to variable name response, the response value is correct (value is "hi WCF").
My confusion is, I think variable name should not matter as long as the layout is the same from client and server side. Any ideas what is wrong?
Server side code:
namespace Foo
{
// NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.
[ServiceContract]
public interface IFoo
{
[OperationContract]
FooResponse Submit(string request);
}
[DataContract]
public class FooResponse
{
[DataMember]
public string response;
}
}
namespace Foo
{
// NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in Web.config and in the associated .svc file.
public class FooImpl : IFoo
{
public FooResponse Submit(string request)
{
FooResponse foo = new FooResponse();
foo.response = "hi WCF";
return foo;
}
}
}
Client side code:
namespace Foo
{
// NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.
[ServiceContract]
public interface IFoo
{
[OperationContract]
FooResponse Submit(string request);
}
[DataContract]
public class FooResponse
{
[DataMember]
// public string responseAliasName;
public string response;
}
}
namespace FooTestClient1
{
class Program
{
static void Main(string[] args)
{
ChannelFactory<IFoo> factory = new ChannelFactory<IFoo>(
"IFoo");
IFoo f = factory.CreateChannel();
FooResponse response = f.Submit("Hi!");
return;
}
}
}
you can use
[DataContract(Name="ResponseAliasName")]
public string response;
on Server side and it will work as you expect, DataContract by default uses field or property name to serialize data, and the server can't find correct data
No, the member name is included in the serialization. If you change it on the client side, it can't deserialize back into that member.
George, why not just use "Add Service Reference" to create your client? As you can see, it's dangerous to create the client-side service contracts by hand.
My confusion is, when
I change client side code from "public
string response" to "public string
responseAliasName", the value of
responseAliasName is null. But when
change back to variable name response,
the response value is correct (value
is "hi WCF").
My confusion is, I think variable name
should not matter as long as the
layout is the same from client and
server side. Any ideas what is wrong?
The variable name that you use locally in your client is totally irrelevant - the server knows nothing about that. Given your code snippet from the client:
ChannelFactory<IFoo> factory = new ChannelFactory<IFoo>("IFoo");
IFoo f = factory.CreateChannel();
FooResponse response = f.Submit("Hi!");
This will work - no problem:
FooResponse myResponseVar1 = f.Submit("Hi!");
and so will this:
FooResponse someReallyCleverVariableNameWhateverItMightBe = f.Submit("Hi!");
But the DataContract of course is a shared element that the service and client have to agree on! You cannot locally change the names of the elements in the data contract - after all, that's what really describes how your calls are going to be turned into an XML message, and these bits and pieces have to stay in sync between the server and the client in order for the client to be able to turn the message received from the server back into an object for you to use.
The ServiceContract and the DataContract must be the same on both ends - that's the basic requirement, otherwise, pretty much nothing goes at all.
Marc