I have MVC client that invokes a WCF service. The MVC client needs to pass one custom header in httprequest. The MVC client is also using Unity for DI.
I have already gone through SO POST and others links but they are all suggesting to use message inspector and custom behavior(which might be the correct way) but i'm looking for quick and dirty way because this will be temporary solution.
// Unity type Registration
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IDocumentManagementChannel>(new PerRequestLifetimeManager(),
new InjectionFactory(f=> CreateDocumentManagementChannel()));
}
private static IDocumentManagementChannel CreateDocumentManagementChannel()
{
var factory = new ChannelFactory<IDocumentManagementChannel>("BasicHttpEndPoint");
var channel = factory.CreateChannel();
// How do i add HttpHeaders into channel here?
return channel
}
In the code above How do i add custom header after i create a channel?
1- Below code should send the soap header from MVC
string userName = Thread.CurrentPrincipal.Identity.Name;
MessageHeader<string> header = new MessageHeader<string>(userName);
OperationContext.Current.OutgoingMessageHeaders.Add(
header.GetUntypedHeader("String", "System"));
2- And this code should read it on WCF
string loginName = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("String", "System");
3- As for the channel, i recommend you create your custom System.ServiceModel.ClientBase as follows:
public abstract class UserClientBase<T> : ClientBase<T> where T : class
{
public UserClientBase()
{
string userName = Thread.CurrentPrincipal.Identity.Name;
MessageHeader<string> header = new MessageHeader<string>(userName);
OperationContext.Current.OutgoingMessageHeaders.Add(
header.GetUntypedHeader("String", "System"));
}
}
4- Create a custom client class that inherits from UserClientBase and use the base channel internally to call your IxxService which is the T here.
Related
The issue has already discussed here, but it did not addressed it quite the way I am looking for.
I have already created a service reference from a client console app in visual studio, but I want to do it programmatically with the following contraint:
From Microsoft Docs - wcf, it obvious that we have to have the service interface reference available to the client. In my case I do have the reference available, instead I have the address where the service is hosted and this address is a dynamic one.
So I want to define a customized client class that will have its object declared with the host address only. Lets take the following snippet as an example:
public partial class CalculatorServiceClient : System.ServiceModel.ClientBase<ICalculatorService>, ICalculatorService
{
}
As you can see that ICalculatorService is available while defining the class. What to do if the interface to the service is not available while defining the class.
You can connect to the WCF service pragmatically without having to use the generated class methods, but note that this can have issues if the service changes in future
The idea is simple .
Create a service contract that matches your service implementation
[DataContract]
public class SomeDataContarctClass
{
[DataMember]
public string SomeMember{get;set;}
etc....
}
Create the interface
public IServiceInterface
{
[OperationContract]
List<SomeDataContarctClass> GetSomeData();
...etc
}
Now this is where you start to Glue things together,
Then create the service
public IServiceInterface CreateIService()
{
EndpointAddress myEndpoint = new EndpointAddress("SERVICE URL");
BasicHttpBinding binding= new BasicHttpBinding();
defaultBinding.MaxReceivedMessageSize = 2147483647;
defaultBinding.MaxBufferPoolSize = 2147483647;
defaultBinding.MaxBufferSize = 2147483647;
defaultBinding.ReaderQuotas.MaxArrayLength = 2147483647;
defaultBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
ChannelFactory<IUpdaterService> myChannelFactory = new ChannelFactory<IServiceInterface>(binding, myEndpoint);
myChannelFactory.Endpoint.EndpointBehaviors.Add(new ServiceInterceptionBehavior());
// Create a channel.
return myChannelFactory.CreateChannel();
}
Then you can call the service using
var myserviceImp = CreateIService();
var data = myserviceImp.GetSomeData();
Is it possible to register a DynamicFeature with an ResteasyClient (Proxy Framework) similar to what can be done on server side?
So something similar to this:
final ResteasyClient client = new ResteasyClientBuilder().build();
client.register(new MyDynamicFeature());
Where MyDynamicFeature implements DynamicFeature
I'm trying to figure out how to have a ClientResponseFilter check the http return status depending on the annotation that is present on the resource method, and the DynamicFeature appeared to be the most promising lead to get access to the ResourceInfo.
So essentially, I want to do something like this:
#POST
#Path("some/path/user")
#ExpectedHttpStatus(201) // <- this would have to be passed on somehow as expectedStatus
User createUser(User request);
And then in the ClientResponseFilter (or any other solution) something like this:
#Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
if (responseContext.getStatus() != expectedStatus) {
// explode
}
}
Cause in the ClientResponseFilter, I don't see any way to know what the resource method is that defined the REST call that the filter is currently analyzing.
And the problem is that the framework right now only checks whether the response status is success, it doesn't check whether it's 200 or 201 and we'd like to refine that.
Here are some articles that seems to explain something very similar, yet this doesn't seem to be working with the ClientResponseFilter / ResteasyClient:
Match Filter with specific Method through NameBinding on RESTeasy
What is the proper replacement of the Resteasy 3.X PreProcessInterceptor?
First of all, I can't take credit for the solution really, but I'm going to paste the answer here.
Also, you could ask why the heck we're doing this? Because we need / want to test that the service returns the right http status, but unfortunately the service we are testing does not always return the same http status for the same http method.
E.g. in the example below, the post returns HttpStatus.OK, and another post method of the same service could return HttpStatus.CREATED.
Here's the solution we ended up with, a combination of ClientResponseFilter:
import java.io.IOException;
import java.util.UUID;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
/**
* {#link ClientResponseFilter} which will handle setting the HTTP StatusCode property for use with
* {#link HttpStatusResponseInterceptor}
*/
public class HttpStatusResponseFilter implements ClientResponseFilter {
public static final String STATUS_CODE = "StatusCode-" + UUID.randomUUID();
#Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
requestContext.setProperty(STATUS_CODE, responseContext.getStatusInfo());
}
}
And ReaderInterceptor:
import java.io.IOException;
import java.lang.annotation.Annotation;
import javax.ws.rs.ServerErrorException;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
/**
* {#link ReaderInterceptor} which will verify the success HTTP status code returned from the server against the
* expected successful HTTP status code {#link SuccessStatus}
*
* #see HttpStatusResponseFilter
*/
public class HttpStatusResponseInterceptor implements ReaderInterceptor {
#Override
public Object aroundReadFrom(ReaderInterceptorContext interceptorContext) throws ServerErrorException, IOException {
Status actualStatus = (Status) interceptorContext.getProperty(HttpStatusResponseFilter.STATUS_CODE);
if (actualStatus == null) {
throw new IllegalStateException("Property " + HttpStatusResponseFilter.STATUS_CODE + " does not exist!");
}
Status expectedStatus = null;
for (Annotation annotation : interceptorContext.getAnnotations()) {
if (annotation.annotationType() == SuccessStatus.class) {
expectedStatus = ((SuccessStatus) annotation).value();
break;
}
}
if (expectedStatus != null && expectedStatus != actualStatus) {
throw new ServerErrorException(String.format("Invalid status code returned. Expected %d, but got %d.",
expectedStatus.getStatusCode(), actualStatus.getStatusCode()), actualStatus);
}
return interceptorContext.proceed();
}
}
We register both those when we create the client:
final ResteasyClient client = new ResteasyClientBuilder().disableTrustManager().build();
client.register(new HttpStatusResponseFilter());
client.register(new HttpStatusResponseInterceptor());
And the SuccessStatus is an annotation that we use to annotate the methods that we want to specifically check, e.g. like that:
#POST
#Path("some/foobar")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#SuccessStatus(Status.OK)
Foobar createFoobar(Foobar foobar);
It's not possible to register a DynamicFeature in your client.
See the DynamicFeature documentation:
A JAX-RS meta-provider for dynamic registration of post-matching
providers during a JAX-RS application setup at deployment time.
Dynamic feature is used by JAX-RS runtime to register providers that
shall be applied to a particular resource class and method and
overrides any annotation-based binding definitions defined on any
registered resource filter or interceptor instance.
Providers implementing this interface MAY be annotated with #Provider
annotation in order to be discovered by JAX-RS runtime when scanning
for resources and providers. This provider types is supported only as
part of the Server API.
The JAX-RS Client API can be utilized to consume any Web service exposed on top of a HTTP protocol, and is not restricted to services implemented using JAX-RS.
Please note the JAX-RS Client API does not invoke the resource classes directly. Instead, it generates HTTP requests to the server. Consequently, you won't be able to read the annotations from your resource classes.
Update 1
I'm not sure if this will be useful for you, but since you would like to access the server resource classes from your client, it would be interesting to mention that Jersey provides a proxy-based client API (org.glassfish.jersey.client.proxy package).
The basic idea is you can attach the standard JAX-RS annotations to an interface, and then implement that interface by a resource class on the server side while reusing the same interface on the client side by dynamically generating an implementation of that using java.lang.reflect.Proxy calling the right low-level client API methods.
This example was extracted from Jersey documentation:
Consider a server which exposes a resource at http://localhost:8080. The resource can be described by the following interface:
#Path("myresource")
public interface MyResourceIfc {
#GET
#Produces("text/plain")
String get();
#POST
#Consumes("application/xml")
#Produces("application/xml")
MyBean postEcho(MyBean bean);
#GET
#Path("{id}")
#Produces("text/plain")
String getById(#PathParam("id") String id);
}
You can use WebResourceFactory class defined in this package to access the server-side resource using this interface. Here is an example:
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/");
MyResourceIfc resource = WebResourceFactory.newResource(MyResourceIfc.class, target);
String responseFromGet = resource.get();
MyBean responseFromPost = resource.postEcho(myBeanInstance);
String responseFromGetById = resource.getById("abc");
I'm not sure if RESTEasy provides something similar to it.
Update 2
RESTEasy also provides a proxy framework. See the documentation:
RESTEasy has a client proxy framework that allows you to use JAX-RS annotations to invoke on a remote HTTP resource. The way it works is that you write a Java interface and use JAX-RS annotations on methods and the interface. For example:
public interface SimpleClient {
#GET
#Path("basic")
#Produces("text/plain")
String getBasic();
#PUT
#Path("basic")
#Consumes("text/plain")
void putBasic(String body);
#GET
#Path("queryParam")
#Produces("text/plain")
String getQueryParam(#QueryParam("param") String param);
#GET
#Path("matrixParam")
#Produces("text/plain")
String getMatrixParam(#MatrixParam("param") String param);
#GET
#Path("uriParam/{param}")
#Produces("text/plain")
int getUriParam(#PathParam("param") int param);
}
RESTEasy has a simple API based on Apache HttpClient. You generate a proxy then you can invoke methods on the proxy. The invoked method gets translated to an HTTP request based on how you annotated the method and posted to the server. Here's how you would set this up:
Client client = ClientFactory.newClient();
WebTarget target = client.target("http://example.com/base/uri");
ResteasyWebTarget rtarget = (ResteasyWebTarget) target;
SimpleClient simple = rtarget.proxy(SimpleClient.class);
simple.putBasic("hello world");
Alternatively you can use the RESTEasy client extension interfaces directly:
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://example.com/base/uri");
SimpleClient simple = target.proxy(SimpleClient.class);
simple.putBasic("hello world");
[...]
The framework also supports the JAX-RS locator pattern, but on the client side. So, if you have a method annotated only with #Path, that proxy method will return a new proxy of the interface returned by that method.
[...]
It is generally possible to share an interface between the client and server. In this scenario, you just have your JAX-RS services implement an annotated interface and then reuse that same interface to create client proxies to invoke on the client-side.
Update 3
Since you are already using RESTEasy Proxy Framework and assuming your server resources implement the same interfaces you are using to create your client proxies, the following solution should work.
A ProxyFactory from Spring AOP, which is already packed with RESTEasy Client will do trick. This solution, basically, creates a proxy of the proxy to intercept the method that is being invoked.
The following class stores the Method instance:
public class MethodWrapper {
private Method method;
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
And the following code makes the magic:
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://example.com/api");
ExampleResource resource = target.proxy(ExampleResource.class);
MethodWrapper wrapper = new MethodWrapper();
ProxyFactory proxyFactory = new ProxyFactory(resource);
proxyFactory.addAdvice(new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
wrapper.setMethod(invocation.getMethod());
return invocation.proceed();
}
});
ExampleResource resourceProxy = (ExampleResource) proxyFactory.getProxy();
Response response = resourceProxy.doSomething("Hello World!");
Method method = wrapper.getMethod();
ExpectedHttpStatus expectedHttpStatus = method.getAnnotation(ExpectedHttpStatus.class);
int status = response.getStatus();
int expectedStatus = annotation.status();
For more information, have a look at the documentation:
MethodInterceptor
ProxyFactory
MethodInvocation
Sorry to bother you guys again.
I am going to consume a WCF service on a server. The service was created by outside. If I look at it in the browser, it is fine. Please see the image below.
To consume it, I add service reference. with the url http://wsvc01/BOERPI/BOERPI.svc
Then I instantiate the proxy by the code.
BOERPI.PostPhoneCallResponse client = null;
client = new BOERPI.PostPhoneCallResponse();
double x = client.ActualCallCharge; // suppose to get a proper value but not
Some of the code of the service is:
[ServiceContract]
public interface iBOERPI
{
[OperationContract]
PostPhoneCallResponse PostPhoneCall(PostPhoneCallRequest objCDRRequest);
[DataContract]
public class PostPhoneCallResponse
{
[DataMember]
public double ActualCallCharge = -1.0;
I assume the service code is 100% right, is any thing wrong when I consume the service?
When I righted click the definition of PostPhoneCallResponse, it is:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="PostPhoneCallResponse", Namespace="http://schemas.datacontract.org/2004/07/nsBOERPI")]
[System.SerializableAttribute()]
public partial class PostPhoneCallResponse : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private double ActualCallChargeField;
Thanks.
client = new BOERPI.PostPhoneCallResponse(); You are trying to use your DataContract here instead of Service client.
Check under Service References for your service name you used in your client application and
use it:
eg.
using(var client = new BingMapsGeocodeService()) // This should be your service client name
{
}
Update:
Sending and Received messages using request and response objects:
You need to create a request object as per your operation shows:
var request = new PostPhoneCallRequest(){ // populate all your properties you need to send to the service};
var client = new BOERPI.MyClient(); // Instantiate your client with the name you have given for your service client.
PostPhoneCallResponse response = client.PostPhoneCall(request); // You are sending your request and getting a response as PostPhoneCallResponse object
Is there a way to create an async client for a synchronous WCF service without adding a service reference? This is for a .NET 4 client.
A service reference in Visual Studio is nothing else than a code generator that creates a proxy class with corresponding data elements necessary to call your web service. Of course you can hand build a proxy if you really want to go over tedious and boring work.
Maybe start by decompiling System.ServiceModel.ClientBase using .net reflector?
Do some research on ChannelFactory: http://msdn.microsoft.com/en-us/library/system.servicemodel.channelfactory.aspx
Even when implementing my own client by wrapping a ChannelFactory, I am still using the Add Service reference in another project to create the class definitions and move them into the real project. That's a good compromise.
Here's a simple async service interface:
[ServiceContract(Name = "IService")]
public interface IServiceAsync
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetStuff(string someData, AsyncCallback callback, object state);
IEnumerable<Stuff> EndGetStuff(IAsyncResult result);
}
The .NET contract might look like this:
[ServiceContract]
public interface IService
{
[OperationContract]
IEnumerable<Stuff> GetStuff(string someData);
}
Then in code, assuming you use HTTP, No security and binary message encoding, something like this (Sorry I haven't compiled any of this, just typed it using some of the code I have written for projects):
//Create a binding for the proxy to use
HttpTransportBindingElement httpTransportBindingElement;
httpTransportBindingElement = new HttpTransportBindingElement();
absoluteServiceUri = new Uri(absoluteServiceUri.OriginalString + BinaryEndpointUri, UriKind.Absolute);
}
//Create the message encoding binding element - we'll specify binary encoding
var binaryMessageEncoding = new BinaryMessageEncodingBindingElement();
//Add the binding elements into a Custom Binding
var customBinding = new CustomBinding(binaryMessageEncoding, httpTransportBindingElement);
// Set send timeout
customBinding.SendTimeout = this.SendTimeout;
var factory = new ChannelFactory<IServiceAsync>(customBinding, new EndpointAddress(absoluteServiceUri, new AddressHeader[0]));
var channel = factory.CreateChannel();
channel.BeginGetStuff(Bla, results => { // Do something }, null);
Greetings one and all!
I'm new to WF 4.0 and WWF in general so forgive me if this seems like a newbie type of question, but believe me I've scoured the depths of the Internet for a solution to this problem, but to no avail.
I have created a sample WF application with a custom CodeActivity that requires an extension be provided, as per below:
public sealed class PreparePizza : CodeActivity
{
public InArgument<Order> Order { get; set; }
protected override void CacheMetadata(CodeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
if (this.Order == null)
metadata.AddValidationError("You must supply an Order.");
metadata.RequireExtension<IPreparePizzaExtension>();
}
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override void Execute(CodeActivityContext context)
{
// Obtain the runtime value of the Text input argument
Order order = context.GetValue(this.Order);
var extension = context.GetExtension<IPreparePizzaExtension>();
extension.Prepare(order);
}
}
public interface IPreparePizzaExtension
{
void Prepare(Order order);
}
I then slot this activity into a workflow service and attempt to consume via my web app by adding a service reference. However, when I add the reference I get:
System.Activities.ValidationException: An extension of type 'PizzaMan.ActivityLibrary.IPreparePizzaExtension' must be configured in order to run this workflow.
Fair enough - of course my activity requires that I pass it an implementation of IPreparePizzaExtension - after all, I've told it to!
So my question is, how on earth do I pass this to the service? I can manage this easily enough in a console app scenario, using the WorkflowInvoker, but I cannot see any obvious way to do this via the service approach. I would assume that obviously a programmatic approach to adding the reference is what's needed, but again I'm at a loss as to precisely how to go about this.
Any help would be greatly appreciated.
Best regards
Ian
The WorkflowServiceHost has a WorkflowExtensions property where you can add the workflow extenstion. There are several ways you can do that. If you are self hosting this is easy as you create the WorkflowServiceHost. If you are usign IIS you need to create a ServiceHostFactory to configure you WorkflowServiceHost. Finally there is an option to add the workflow extension in the CacheMetadata of your activity using the metadata.AddDefaultExtensionProvider() function.
Solved it as follows, self-hosting style:
static void Main(string[] args)
{
Workflow1 workflow = new Workflow1();
// Provide some default values; note: these will be overriden once method on the service is called.
workflow.productID = -1;
Uri address = new Uri("http://localhost:1234/WorkflowService1");
WorkflowServiceHost host = new WorkflowServiceHost(workflow, address);
// Behaviours
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
host.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
// Persistence
var connStr = #"";
var behavior = new SqlWorkflowInstanceStoreBehavior(connStr);
behavior.InstanceCompletionAction = InstanceCompletionAction.DeleteNothing;
behavior.InstanceLockedExceptionAction = InstanceLockedExceptionAction.AggressiveRetry;
behavior.InstanceEncodingOption = InstanceEncodingOption.None;
host.Description.Behaviors.Add(behavior);
// Add extension implementations
if (!TEST_MODE)
{
host.WorkflowExtensions.Add(new MyExtension());
}
else
{
host.WorkflowExtensions.Add(new MyExtensionTest());
}
host.Faulted += new EventHandler(host_Faulted);
host.Open();
foreach (System.ServiceModel.Description.ServiceEndpoint endpoint in host.Description.Endpoints)
{
Console.WriteLine(endpoint.Address);
}
Console.WriteLine("Listening...");
Console.ReadLine();
host.Close();
}
My toolkit has configuration support for this. See http://neovolve.codeplex.com/wikipage?title=Neovolve.Toolkit.Workflow.dll%20-%201.1
There is also this method of doing things:
http://wf.codeplex.com/wikipage?title=How%20do%20I%20add%20an%20extension%20to%20a%20WCF%20Workflow%20Service?