Creating a WCF Web Api Client - wcf

I've been using the WCF Web Api recently and i've been using the WCF Web API Test Client that is built in to it to test my created webservices.
I am wanting to create a proxy in code built off of the interface rather than run svcutil.exe to create a proxy.
My webservice is working fine, however when I use fiddler to examine the message that is sent, it is putting in a namespace into the xml message.
Below is the code I use to send the request.
RegisterRequest registerRequest = new RegisterRequest
{
Email = "test#test.com",
Firstname = "firstname",
Lastname = "lastname",
Password = "password"
};
var factory = new ChannelFactory<IAccountApi>(new WebHttpBinding(), "http://localhost/WebServices/api/account");
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
var proxy = factory.CreateChannel();
proxy.Register(registerRequest);
This request below is generated via the client, and it fails, returning a 500 internal server error
<RegisterRequest xmlns="http://schemas.datacontract.org/2004/07/ServiceModel.Accounts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Email>test#test.com</Email><Firstname>firstname</Firstname><Lastname>lastname</Lastname><Password>password</Password></RegisterRequest>
Using the same headers when I send using the api test client the following message passes
<RegisterRequest><Email>test#test.com</Email><Firstname>firstname</Firstname><Lastname>lastname</Lastname><Password>password</Password></RegisterRequest>
The only difference being the namespace has been removed.
Some final points,
1) If I were able to remove this namespace the request would work
2) I am not sure if ChannelFactory can be used in conjunction with WCF Web Api. The reason being http://wcf.codeplex.com/releases/view/73423 states "[ServiceContract] is no longer required on the Web API class definition", yet Channel Factory requires it.
3) All the examples so far from the WCF Web API look like the following
HttpClient client = new HttpClient();
Contact contact = new Contact() { Name = name };
var response = client.Post("http://localhost:9000/api/contacts/",
new ObjectContent<Contact>(
contact, JsonMediaTypeFormatter.DefaultMediaType));
Should I be using HttpClient for my requests instead of channel factory?
Regards,
Andrew

It appears that the IAccountApi, which you do not show, is defining a namespace for the service contract. If you really want an empty namespace (not best practice) try something like this:
[ServiceContract(Namespace="")]
public interface IAccountApi
{ ... }
If the namespace is not defined for IAccountApi, check the [DataContract] of RegisterRequest.

I ended up using HttpClient class, it allows GET, POST, PUT and DELETE which was fine for WCF Web API (now called http://www.asp.net/web-api)
http://msdn.microsoft.com/en-us/library/system.net.http.httpclient.aspx
as far as building a rest proxy using codegen or being dynamic see this article
ReST Proxy Object Generator

Related

Consume SOAP service in .NET Core using SAML with signed XML

We are converting some code from .NET Framework to .NET Core. Some services are using SOAP messages with a signed header. Using SoapCore we've been abled to create a service which supports signed XML (and the necessary validations). However, we are now creating a client which should be able to consume such a service (in .NET Core).
Basic code (performing the request, no signing):
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress(new Uri("https://myserver/mysoapendpoint/"));
var channelFactory = new ChannelFactory<ISampleService>(binding, endpoint);
var serviceClient = channelFactory.CreateChannel();
var result = serviceClient.Ping("hey");
I can't find any way to make the service send an XML. In .NET Framework we could do it the following way:
using (ChannelFactory<ISampleService> factory = new ChannelFactory<ISampleServiceChannel>(tokenBinding, endpointAddress))
{
factory.Credentials.UseIdentityConfiguration = true;
using (ISampleServiceChannel proxy = factory.CreateChannelWithIssuedToken(myToken))
{
var result = proxy.Ping("hey");
}
}
Stuff like CreateChannelWithIssuedToken no longer seems to be implemented in .NET Core. If I could inject something which would sign the XML than I could do the writing myself. However, I'm unable to find the correct way to achieve this goal.
We cannot change to another implementation of security as we are not controlling the clients/services... (Clients from different organizations will interact this way...)
Many thanks for your replies.

Access the underlying Request(WebRequest or HTTPRequest) object in WCF for Digest PreAuthentication

We are exposing the Entity objects through WCF Services. To retrieve the entities we make several requests through WCF, close to a 100 or more. We recently switched to Digest Authentication and noticing that every single server request is issuing a 401. This creating twice as much load on the server and since we have very large "posts", this will create additional traffic lag. The goal is to have only a single Challenge(401) from the server and the rest of the requests should include the Auth header so the server doesn't issue a 401. Since Digest is a challenge based protocol with an expiring nonce, even though we may not fully eliminate the 401's but at least avoid them for every request. Since we control both server and client we want send the Digest Auth header included on every request.
There is a Pre-Authenticate property in .NET 2.0 webservices Style Web Reference Proxy/Client(that inherits SOAPHttpClientProtocol) that allows the Auth header to be included with the request, but with a WCF Services Web Reference client(that uses ChannelFactory) there isn't. There is a clear difference in the Request/Response traffic when this property is set and when it isn't. Since this is Digest Authentication(NOT Basic) I cannot add the Auth header manually during BeginRequest with a ClientMessageInspector.
NetworkCredential creds = new NetworkCredential("username", "pass", "domain");
//using .NET 2.0 "Web Reference" Style client that uses inherits SoapHttpClientProtocol:
webReferenceClient = new Service1();
webReferenceClient.Credentials = creds;
//**Pre Authenticate **
webReferenceClient.PreAuthenticate = true;
string resp1 = "";
for (int i = 0; i < 3;i++)
resp1 = resp1 + webReferenceClient.SayHello("jack");
//using WCF "Service Reference" Client that uses ChannelFactory
serviceReferenceClient = new Service1Client();
serviceReferenceClient.ClientCredentials.HttpDigest.ClientCredential = creds;
serviceReferenceClient.ClientCredentials.HttpDigest.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
string resp="";
for (var i = 0; i < 3;i++)
resp = resp + serviceReferenceClient.SayHello("jack");
Fiddler trace with .NET 2.0 Style Web Reference Client, with Preauthenticate set. Notice that there is only one 401 and rest of the requests have Auth header.
Trace with WCF Style Service reference Client. Every single request generated a 401 from the server:
I see two options:
Switch our Client code to use .NET 2.0 style Web reference Client,
this will be a big move since we are doing some custom Fault handling.
Find a way to get to the WebRequest or the HTTPRequest object of the WCF
ChannelFactory and set the PreAuthenticate Property.
How to get to the actual WebRequest object??
Are there any other options??

WCF and Data Transfer Object

I am stuck on this simple question. In my console application, I want to consume a wcf service. So I add the web reference to the project and call it. That is it.
But why I saw some examples especially using RESTSHARP, they never add web reference. They just use so called "DTO" to return object by the service and consume it.
I hope somebody can clarify the concepts for me. Is DTO used inside WCF?
sample:
private static List<ApplicationDTO> features;
RestClient client = new RestClient("http://" + baseUrl + "/FacilityData.svc");
var request = new RestRequest(Method.GET);
request.Resource = "/GetFeatures";
request.Parameters.Clear();
request.AddParameter("Id", 888);
var response = client.Execute(request);
features = JsonConvert.DeserializeObject<List<ApplicationDTO>>(response.Content);
from this post:
For REST service, it provides a generic way for WCF service consuming
which doesn't rely on the SOAP. That's why we no longer need "Add
ServiceReference..." for consuming it. REST service operations can be
accessed through standard HTTP GET/POST request, so any webrequest
enabled client can consume it. For example, you can use HttpWebRequest
to invoke a REST operation and use LINQ to XML to load and extract
values from the response XML data. It's very flexible.
DTO, usually used for Data Transfer Object - is nothing more then entity you want to pass as parameter / receive as a result.
In your example, ApplicationDTO - is probably some entity to hold Data about Application Feature object (Name, Type, ...)

How to allow all Operations and Namespaces

I'm new to WCF, but not new to C# and .Net. and am using Visual Studio 2008 and .Net 3.5.
I'm trying to build a Web Service that can receive any inbound Request XML and any namespaces. It would behave like a transparent receiver and simply intake the inbound request XML.
Once I get the request I'm going to pass it to some custom .Net C# Project to invoke a MQPUT to IBM MQ Series.
Right now I have the WCF Web Service Application receiving a generic inbound operation called RunTest(). I consume the WSDL into SoapUI, build a sample request and breakpoint and it works. But, when I try to pass our company request XML it doesn't land on the breakpoint.
Here is the ServiceContract and Operation:
[ServiceContract(Name="IService1",Namespace="cfg-env=http://www.co.com/schemas/cfg- env/")]
//[ServiceContract]
public interface IService1
{
[OperationContract]
void RunTest();
[OperationContract]
void CFX();
Here is the Method for the Operation:
public void RunTest()
{ <<<it does break here using the request from the WSDL
string serviceName;
string queueManager;
string queue;
string requestMessage;
//Capture the Service Name
serviceName = "";
//Save the QueueManager
queueManager = "";
//Save the Request Queue
queue = "";
//Save the Message
requestMessage = "";
//Call MQ Put
Engine eng = new Engine();
try
{
eng.Put(serviceName, queue, requestMessage, queueManager);
}
The main thing I need to do is receive the inbound XML, interogate it for a few pieces of information and call this Method to do the MQPUT function on MQ.
The inbound namespace will look like the above but I'd like to ensure I can receive and interogate any XPATH that may be namespace qualified. If I have to I can work with the cfg-env namespace prefix exclusively as our services do use that as a standard.
What are my key hurdles in doing this in VS 2008 WCF? If you have any links please pass them along if you can.
I believe you specify the name property on the OperationContract attribute as "*" to accept all requests. To make the parameter itself schema agnostic, it should be of type System.ServiceModel.Channels.Message.
What you are building is a "WCF router".
Included in the latest .NET release is a configurable Routing Service.
If the routing service doesn't meet your needs, building your own router is possible but can get really complicated when secure messages are a requirement. This set of MSDN articles is the best resource. They answer your question of how to have a service accept any message, and then continue on into addressing and security issues.
Building a WCF Router, Part 1
Building a WCF Router, Part 2

How to Consume MVC 4 WebApi Service

I am new to Web Api world and I see a lot of potential for in the new MVC 4 Web Api. I have generated a WCF Web Service but was planning to get to know Web-APIs and their web service capabilities. Now, is MVC 4 Web-Api Service more as front end? I wrote a sample Service by following some examples online in MVC 4 Web Api but how do I consume the Service in just a basic console app? I have figured out the only way to consume it is by using HttpClient are there other ways? I am used to ASP.NET Web Service and WCF Web Service as where you reference it as a service in your references and then you are able to see all of its objects, properties to make appropriate calls.
What happens if web-api is requesting a object "Task" for post method as an example how am I able to fill an object "Task" and post it back to the web-api? As in WCF I am able to see that "Task" object and its properties because of WSDL so I am able to fill them and send it back to the service how is that done in web-api service?
The webservice would be used internally is it worth it to have an web-api service?
Thank you so much for helping clearing some question of what I have about web-api services.
---Edit as per Comment---
This screenshot shows a possible structure which you can approach. Of course, you can take a design that best suit your application.
So ControllerLib is a separate Class Library project which is brought into the main project as a Service Reference (which is not shown in the screenshot but should be inside the References folder of the SecondMVCApplication project). The two controller file (HomeController.cs and LocationController.cs is a controller file that implemented the Controller class, which is the same thing as a Controller file when you create a new MVC4 application using the template)
So for your question regarding if there is a SVC file. NO. In MVC 4, there is no such thing as a SVC file whether the application is one project or a combination of multiple project (unless I am mistaken). Inside the SecondMVCApplication, there is a file called RouteConfig.cs which holds the routing URL and as long as you add the Service Reference and there controller function exists. The code will run. Also the sample screenshot I showed also includes a WebApiConfig.cs file. You can use that file to do API stuff for mobile if you need. So, the regular RouteConfig.cs handles website request and the WebApiConfig.cs handles API request.
Good to Note: If you are using a Model project as a separate project (which I know you will as it is a M-V-C project...DUH!!). Make sure you put your connection string inside the web.config main project (in this case, the SecondMVCApplication). I remember I was stuck in this problem for 3 days (8 hours each) trying to fix this problem. Hope you don't run into it.
---End Edit---
The following answer to your question is mostly based on my knowledge and may or may not be true to all users.
Is MVC 4 Web-Api Service more as front end?
This depends on how you look at it. Typically, a Web-API service is more suited for creating back-end service to provide a data payload to different platforms, like mobile, desktop apps and so on. However, a MVC4 Internet Application will have front-end aspects in them, namely the Views, which end-users sees.
How do I consume the Service in just a basic console app?
AFAIK, there is two way to do this. One if to consume the APIs as a Service Reference. Another is to use HTTP operation (which I will mention in your question regarding the HTTP client and reserve this answer using the Service Reference method).
This depends on how your application is done. Like I said, if it is a website, your MVC pattern will not need to do anything, but the Models, Views and Controllers all are designed to work together without using any service.
Although, as I mentioned in the comments to the questions, if it is a big application then you will need to break them into different projects that will make the app modular and nimble. So you will end up creating different Service Library. If you go down the Service Library road, then you just make use of the Add Reference option to bring in your API/Projects/Whatever-you-call-it into the project. (For this, I normally put all project inside a single solution and let Visual Studio manage the build order as I am lazy to write up a build script).
Similarly, the same logic could be applied when consuming your web service in a console app.
I have figured out the only way to consume it is by using HttpClient are there other ways?
One way to consume web APIs is using HTTP. Are you aware of how to write http request headers and handle http response. If so, this is the second way I mentioned. You call the web service through it's URL and then get the data and do whatever work. If your answer to use http in console app is NO, then look at this post: Create HTTP post request and receive response using C# console application
What happens if web-api is requesting a object "Task" for post method as an example how am I able to fill an object "Task" and post it back to the web-api?
I think I indirectly answered this in your previous answer (assuming you are going to take the HTTP road). If not, then comment and I'll see if I can find some resource for you.
The webservice would be used internally is it worth it to have an web-api service?
I sort of answered this in the comment to the question. Ask if you need clarification.
Hope all this helps.
you can create your own Client Service class that will serve for every request.
public class ClientService
{
#region async helper methods
private static string m_mediaTypeHeaderValue= "application/json";
static HttpClient client = new HttpClient();
static HttpClient createHttpClientInstance()
{
return client ?? new HttpClient();
}
// SELECT
internal static async Task<T> Get<T>(string endpoint)
{
client= createHttpClientInstance();
var response = await client.GetAsync(endpoint);
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JsonConvert.DeserializeObject<T>(content));
}
// INSERT
static async Task<T> Post<T>(string endpoint, object data)
{
client = createHttpClientInstance();
var httpContent = new StringContent(JsonConvert.SerializeObject(data));
httpContent.Headers.ContentType = new MediaTypeHeaderValue(m_mediaTypeHeaderValue);
var response = await client.PostAsync(endpoint, httpContent);
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JsonConvert.DeserializeObject<T>(content));
}
// UPDATE
static async Task<T> Put<T>(string endpoint, object data)
{
client = createHttpClientInstance();
var httpContent = new StringContent(JsonConvert.SerializeObject(data));
httpContent.Headers.ContentType = new MediaTypeHeaderValue(m_mediaTypeHeaderValue);
var response = await client.PutAsync(endpoint, httpContent);
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JsonConvert.DeserializeObject<T>(content));
}
// DELETE
static async Task<T> Delete<T>(string endpoint)
{
client = createHttpClientInstance();
var response = await client.DeleteAsync(endpoint);
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JsonConvert.DeserializeObject<T>(content));
}
#endregion
}