I have several webAPIs developed in MVC WebAPI such as
public IHttpActionResult SendBroadcast(FinalPayload FinalPayload)
And I want to call another web api from inside this API. All my APIs are in the same application. The signature of the second API is
public IHttpActionResult SendMessage(Notifications)
From the first API i tried
this.SendMessage(Notifications)
and got error message something like reference to static object ....
I wanted to know if this way of calling webAPI is allowed or do I have to invoke a web client or similar such.
Any help in this will be much appreciated.
1st approach
You have to redesign the code in your application i.e. Solution.
Create a class library project. Create an interface for the logic/functions which are common and consumed by different projects.
Implement the interface in the class library project.
In different projects(i.e. WebAPI projects) use the interface to access the common functionality.
2nd Approach
As thought by you, of-course you can create a web client to access the Web API in another project.
Its not a good design and your problem is not ACTUALLY solved (just circumvented).
Poor efficiency, as webclient will use http request to access the code in same solution.
For future maintenance you may end up creating multiple web clients.
No, as usual you'll need to create a new web client in order to consume the API.
What #Marcus H has suggested in the comment is doable too, just wrap the logic inside second API into a separate method (be it instance or static) and invoke it from your first API will do the trick.
Yes you can. You can create a webClient in your controller method method2 that calls method1.
This is a little helper class you could use to help you:
namespace Api.Helpers
{
public static class ApiHelpers
{
private static string HttpGet(string url)
{
WebRequest request = WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();
return responseFromServer;
}
public static string HttpPostJson(string url, string json)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
};
}
}
}
If you want Cookie based authentication, then just use RestSharp instead.
If you use Postman the Chrome extension tool, then if you can access your endpoint, you can automatically generate your C# code.
Simply put the webclient code within the Controller method, and one API call will effectively chain to another.
so in your ApiController you'd write something like:
IHttpActionResult method1() {
var result = ApiHelpers.HttpGet("http://thing.com/test");
return Ok(result);
}
Related
I'am trying to pass values from a controller to another controller in another domain. I'am adding data to a NameValueCollection and pass it to another controller [httppost] method and receiving data there mapped to a Model same as i passed from.
Currently i'am running it locally by opening two instance of VS simultaneously. When the both VS is opened the values are passed correctly and the information is written to db correctly and i receive a response like "{byte[0]}". Now when i try stopping the destination controller Project and try to submit data then it wont work but still i get the same response as "{byte[0]}". Can somebody please help me how to return the response command in this scenario. Is there a way a understand the UploadValues are completed or not completed.
.........
.........
NameValueCollection resumeDetails = new NameValueCollection();
resumeDetails.Add("FirstName", "KRIZTE");
byte[] res = this.Post(ConfigurationManager.AppSettings["RedirectionUrl"].ToString(), resumeDetails);
return View("Index");
}
public byte[] Post(string uri, NameValueCollection resumeDetails)
{
byte[] response = null;
WebClient client = new WebClient();
response = client.UploadValues(uri, resumeDetails);
return response;
}
You should not use the WebClient because of problems like this.
Microsoft implemented HttpClient class as a newer API and it has these benefits:
HttpClient is the newer of the APIs and it has the benefits of
has a good async programming model
1- being worked on by Henrik F Nielson who is basically one of the inventors of HTTP, and he designed the API so it is easy for you to follow the HTTP standard, e.g. generating standards-compliant headers
2- is in the .Net framework 4.5, so it has some guaranteed level of support for the forseeable future
3- also has the xcopyable/portable-framework version of the library if you want to use it on other platforms - .Net 4.0, Windows Phone etc.
so I'm gonna show you an example of using HttpClient:
var uri = "http://google.com";
var client = new HttpClient();
try
{
var values = new List<KeyValuePair<string, string>>();
// add values to data for post
values.Add(new KeyValuePair<string, string>("FirstName", "KRITZTE"));
FormUrlEncodedContent content = new FormUrlEncodedContent(values);
// Post data
var result = await client.PostAsync(uri, content);
// Access content as stream which you can read into some string
Console.WriteLine(result.Content);
// Access the result status code
Console.WriteLine(result.StatusCode);
}
catch(AggregateException ex)
{
// get all possible exceptions which are thrown
foreach (var item in ex.Flatten().InnerExceptions)
{
Console.WriteLine(item.Message);
}
}
I am working on a c# console application where I am making a Http Post request to a web api by using xml file and I'm kind of new to XML and web services but I figured out the following code for the request but failed to pass xml data to the method
static void Main(string[] args)
{
string desturl=#"https://xyz.abcgroup.com/abcapi/";
Program p = new Program();
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
}
public string WebRequestPostData(string url, string postData)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.ContentType = "text/xml";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postData);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
return sr.ReadToEnd().Trim();
}
}
}
For obvious reasons the above code throws 404 error as I think I am not passing the xml data properly
May I know how I can fix this?
You're not posting xml, your posting the string C:\Applications\TestService\FixmlSub.xml
Change your method call from:
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
to
var xml = XElement.Load(#"C:\Applications\TestService\FixmlSub.xml");
System.Console.WriteLine(p.WebRequestPostData(desturl, xml.ToString(SaveOptions.DisableFormatting));
If you are trying to learn post / receive, go for it. But there are open source libraries that are already well tested to use if you want to use them.
The non-free version of Servicestack.
And their older free-version. I think the older free version is great. I've never tried the newer one. You deal with objects, like say an Employee and pass that to the library and it does the translation to xml or whatever the web-service wants.
You can post whole strings if you want. They have great extension methods to help you with that too.
In the context of .NET...
For a web application I'm developing, I have the following architecture (from topmost to bottommost, loosely speaking):
Web API 2.0 controllers in the Web layer
Service layer (more or less one-to-one with controllers; e.g. ProjectsController calling into a ProjectsService)
Repository layer, which incorporates the Model layer and references to the .NET RavenDB Client
Ninject for DI
All calls by the controllers into the service layer return something: Create returns the object POST-ed; Update returns the object PUT-ed; Delete returns a copy of the object DELETE-ed, etc.)
All calls from the client (javascript in the browser) into the Web API are AJAX
Focusing now on one controller in particular and two services, I have the following: A ProjectsController ("PC") calling into the ProjectsService ("PS"), which has a SmartyStreetsGeocodingService ("SSGS") injected into it and that the ProjectsService calls. I wrote SSGS as a synchronous service initially just for testing purposes. But now the time has come to convert the sync call out to the Smarty Streets RESTful API to an async call. I'm having a timing issue right now that is related to synchronicity, and the GeocodingResult it processes too soon.
My question really revolves around architecture. Also, I would like to stay within the confines of just converting from sync to async (I'm aware of other approaches, such as .NET Service Bus, SignalR, etc., all of which I'll look at later).
What exactly should be async?
Consider the following code from the SSGS:
using (var response = request.GetResponse() as HttpWebResponse)
{
if (response == null) return geocodingResult;
var jsonSerializer = new DataContractJsonSerializer(typeof(CandidateAddress[]));
var stream = response.GetResponseStream();
if (stream == null) return geocodingResult;
var objResponse = jsonSerializer.ReadObject(stream);
jsonResponse = objResponse as CandidateAddress[];
}
if (jsonResponse == null || jsonResponse.Length == 0) //<-- Executes too soon
{
geocodingResult.IsVerified = false;
return geocodingResult;
}
geocodingResult.IsVerified = true;
The fragment above is what I wish to convert to async as the portion of code immediately following the using statement executes too soon. But that leads to questions:
When I do convert to async, what should be asynchronous exactly?
Just the method in which the call to SSGS is located?
Should the PS itself make an async call into the SSGS?
Does the PC need to be async as well?
Should the call from the PC into the PS be async?
Thank you.
The most important thing that should be asynchronous in your case is the HTTP call to the remote service. From there on, everything that is calling this service should of course be asynchronous.
At the end of the day you should have an asynchronous controller action in your outermost layer (the Web API):
public async Task<HttpResponseMessage> Get()
{
var request = WebRequest.Create("http://google.com");
using (var response = await request.GetResponseAsync())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
string responseContent = reader.ReadToEnd();
return Request.CreateResponse(HttpStatusCode.OK, responseContent);
}
}
So as you can see from this controller action I have used an asynchronous Httprequest. So in order to achieve that in your current design you need to make everything asynchronous and expose async methods in your service layer as well so that you can async/await on the result that's gonna get you the JSON from the service layer.
In my example I have simply returned a string from the remote HTTP call but you could easily adapt your service layer to return complex objects as well:
public async Task<MyModel> GetMyModelfromRemoteServiceCall();
{
var request = WebRequest.Create("http://google.com");
using (var response = await request.GetResponseAsync())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
string responseContent = reader.ReadToEnd();
return JsonConvert.DeserializeObject<MyModel>(responseContent);
}
}
You could then trivially easy await on this service layer method from your async Web API controller action.
My web application needs to be able to go and get all my projects from Paymo http://api.paymo.biz/
I am familiar with JSON and XML, but what I'm wondering is, how does one interact with the api (make calls to it).
I would ideally like to make a class in ASP .Net such as PaymoManager(int apikey....)
From there I can wrap the functionality I need. I just need to understand, how do I call functions of the API and how do I get the response. I am not familar with web apis.
Edit: Could you give me an example of this, even with some abstract url. I need this done server side in a CS file.
Basically a simple example that calls someurl.com/somerequest and then how do you receive the JSON or XML... how does this work in terms of a class. I want this in a class.
http://api.paymo.biz/docs/misc.overview.html
To perform an action using the Paymo API, you need to send a request
to the Paymo webservice specifying a method and some arguments, and
will receive a formatted response.
This means that you can use WebClient to download a string from a url:
WebClient client = new WebClient();
string reply = client.DownloadString (address);
Depending on the format you specify, you can parse the reply as XML or JSON.
XDocument xml = XDocument.Parse(reply);
// where ReplyType is a class that defines public
// properties matching the format of the json string
JavaScriptSerializer serializer = new JavaScriptSerializer();
ReplyType abc = serializer.Deserialize<ReplyType>(reply);
If you are using .NET 4.5, you might consider using HttpClient like so:
static async void Main()
{
try
{
// Create a New HttpClient object.
HttpClient client = new HttpClient();
// fill in the details in the following string with your own KEY & TOKEN:
string requestUrl = "https://api.paymo.biz/service/paymo.auth.logout?api_key=API_KEY&format=JSON&auth_token=AUTH_TOKEN"
HttpResponseMessage response = await client.GetAsync(requestUrl );
response.EnsureSuccessStatusCode();
string responseBodyJSON = await response.Content.ReadAsStringAsync();
// Above three lines can be replaced with new helper method in following line
// string body = await client.GetStringAsync(uri);
Console.WriteLine(responseBodyJSON );
// Now you can start parsing your JSON....
}
catch(HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ",e.Message);
}
}
How to call WCF Data Services Operations from the WCF Services Client ?
I have this operation on my service :
[WebInvoke(Method="POST")]
public void Add(int ContractId, string Partners)
{
...
}
How do I call this operation from my client ? my client is a C# based application. bearing in mind that the Partners string is a very very long one. it's a concatenation of the partners Ids like : "1,2,3,4, ... 990".
I have tried doing the following :
string requestString = string.Format("Add?contractId={0}&Partners={1}", ContractId, groupIdParam);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceUrl +
requestString);
request.Method = "POST";
var response = request.GetResponse();
but I receive the error : "HTTP 414 : Request Uri too long"
Currently OData doesn't support passing parameters for service operations (that's what the WebInvoke method is) in the body of the POST request. All the parameters are passed in the URL, and thus they have to be pretty small (usually something below 2048 characters, depends on your web server, proxies and so on).
Actually, you aren't performing a POST-request. A POST request provides the information in the request-body, which is why it is used especially for large data-sets. You have to provide both contractId and partners in the request-body. You can use the HttpWebRequest.GetRequestStream() method to get a stream, to which you then write the parameters.
This link http://en.wikipedia.org/wiki/POST_(HTTP) describes the structure used to specify the name-value pairs within the request-body.
So you could write something like this (untested):
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceUrl + "Add");
using (Stream bodyStream = request.GetRequestStream())
using (StreamWriter writer = new StreamWriter(bodyStream))
{
writer.Write("contractId: {0}", contractId);
writer.Write("partners: {0}", String.Join(",", partners);
}
request.GetResponse();
Edit
As Vitek Karas stated this isn't possible. I just looked at it from a client perspective not the service.