In my application, it is calling webapi, and application is in MVC5. Now I have many more methods in application project. So I want to create one common(global) method to call the api. Methods which are used for get content those are working fine, but methods, those are used to post(means save data to DB kind of) data, getting error like this. Code is like below:
public static string SendDataToAPI(dynamic objCommon, string urlParameters, ref string errorMessage)
{
try {
string url = ConfigurationSettingHelper._BaseUrl;
string strJson = string.Empty;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var response = client.PostAsJsonAsync(urlParameters, objCommon);
if (response.Result.IsSuccessStatusCode)
{
strJson = response.Result.Content.ReadAsStringAsync().Result;
}
else {
errorMessage = response.Result.Content.ReadAsStringAsync().Result;
}
return strJson;
}
}
catch (Exception ex) {
errorMessage = ex.Message;
return errorMessage;
}
}
So, my question is how can I pass dynamic object type in PostAsJsonAsync method? How can I set this kind of method for common use?
Try something below where the post data model generically accepts any type and complex object also should be wrapped into single model.
public async virtual Task<string> ExecuteHttpApiCall<TModel>(TModel model, string url)
{
HttpResponseMessage response;
using (var client = new HttpClient())
{
if (model != null)
{
response = await client.PostAsJsonAsync(url, model);
}
else
{
response = await client.GetAsync(url);
}
return await response.Content.ReadAsStringAsync();
}
}
Related
I have my Web Api on a production server online and working well in postman and in Xamarin forms so far until I needed to do a Get Request and does not return any data. Infact it stops at the GetAsStringAsync line and does not continue. Instead, it jumps out of the method and then nothing more.
Does any one know what the problem could be? I have checked and made sure my Internet is working and the Uri too.
This is where I am doing my Get in Xamarin forms:
public async Task<List<OfferModel>> AllOffers()
{
var httpclient = new HttpClient();
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", Settings.AccessToken);
//it does not continue after this line, it jumps out of the method instead
var response = await httpclient.GetStringAsync(UrlConstants.offerurl);
var data =JsonConvert.DeserializeObject<List<OfferModel(response);
return data;
}
Solution 1
Can you try access task via awaiter it may be wait until result when responded
public class HttpHelperService
{
public async Task<List<OfferModel>> AllOffers()
{
List<OfferModel> result;
string responseBody;
using (HttpClient client = new HttpClient())
{
try
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", Settings.AccessToken);
HttpResponseMessage response = client.GetStringAsync(new Uri(UrlConstants.offerurl)).GetAwaiter().GetResult();
result = JsonConvert.DeserializeObject<List<OfferModel>>(response);
}
catch (Exception ex)
{
result = null;
}
return result;
}
}
}
Solution 2
public class MyPage : ContentPage
{
//Here is your page constructor
public MyPage()
{
GetServices(); //--> call here without awaiter
}
}
//Here is your awaiter method
private async void GetServices()
{
LoadingPopupService.Show();
var result = await HttpService.AllOffers();
LoadingPopupService.Hide();
}
//Here is your service.
public async Task<List<OfferModel>> AllOffers()
{
var httpclient = new HttpClient();
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", Settings.AccessToken);
var response = await httpclient.GetStringAsync(UrlConstants.offerurl);
var data =JsonConvert.DeserializeObject<List<OfferModel(response);
return data;
}
I have created web api and calling service method from MVC application. I have implemented authentication in Web Api.
I have created Generic type method from which I call my service method and returning result to action method like below:
public async Task < T > GetWSObject < T > (string uriActionString)
{
T returnValue = default (T);
try
{
using(var client = new HttpClient())
{
//client.BaseAddress = new Uri("http://localhost:50524/");
//client.DefaultRequestHeaders.Accept.Clear();
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HttpClient cons = new HttpClient();
client.BaseAddress = new Uri("http://localhost:50524/"); // Web Service URL
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var data = Encoding.ASCII.GetBytes("Ankita:ankita12");
var header = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(data));
client.DefaultRequestHeaders.Authorization = header;
HttpResponseMessage response = await client.GetAsync(uriActionString);
response.EnsureSuccessStatusCode();
returnValue = JsonConvert.DeserializeObject < T > (((HttpResponseMessage) response).Content.ReadAsStringAsync().Result);
}
return returnValue;
}
catch (Exception e)
{
throw (e);
}
}
Moreover, I am calling this method from my action method like:
public async Task<ActionResult> ViewAuthor(Author author)
{
ViewBag.Message = "Your Author page.";
Author authors = new Author();
string urlAction = String.Format("api/Authors/GetAuthor/{0}", author.Id);
authors = await GetWSObject<Author>(urlAction);
return View(authors);
}
Now how can I return message from catch block in case of Unauthorized access as GetWSObject method is having generic type.
I just want to display message on my Author detail page like you are unauthorized to perform this action. How can I do it?
You have two choices
Add a type to wrap the result for example WSResult<T>. Then your method will return that type. It can look like this
public class WSResult
{
public T Result { get; set; }
public HttpStatusCode StatusCode { get; set; }
}
Then your method will return this type and consumers will check the status first. This is similar to how HttpResponseMessage works. You can copy ideas from it.
In this case your method has a signature like this
public async Task<WSResult<T>> GetWSObject<T> (string uriActionString)
You return things from it like this
return new WSResult<T> { Result = returnValue, Status = HttpStatusCode.OK }
Or in the catch
return new WSResult<T> { Result = returnValue, Status = HttpStatusCode.InternalServerError }
Note that the actual status code in the exception may differ and you should catch the proper exception. You can also use a boolean instead of HttpStatusCode and call it IsSuccessful or something. You can also roll your own enum with values suitable for your code.
Alternatively you can throw an exception that contains the status code. The second way is easier to implement and requires less refactoring but the first one is the recommended way.
I want to save data to database in MVC application. I have below class which calls the webapi1 service post method. Here Sample is a model object. I have a view which uses the Sample object. I want to inert the Sample Object data to db using the service call.
public SampleTestCreate(Sample)
{
string uri = baseUri + "Test";
using (HttpClient httpClient = new HttpClient())
{
Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(uri, new StringContent(JsonConvert.SerializeObject(Test)));
// Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(uri, Test);
var data = response.Result.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObjectAsync<Test>(response.Result.Content.ReadAsStringAsync().Result).Result;
}
}
// POST api/Sample
public HttpResponseMessage PostSample(Sample Sample)
{
if (ModelState.IsValid)
{
db.Samples.Add(Sample);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, Sample);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = Sample.SampleID }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
Here my service post method is getting called , but the "Sample" objects all the properties values are coming null. The model object binding is not happening.
I am getting data from a web api by making httpclient calls from various MVC controllers. Because I have to do it many times, I made a generic method that I can reuse by just passing in the api url and the model return type. It works fine, but I am concerned I am loosing the oppurtunity to have different methods, like GetPeople, GetPersonById, etc. Is there a downside to what I am doing?
Utilities.cs:
public static T GetDataFromWebService<T>(T model, string svcEndPoint)
{
HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync(svcEndPoint).Result;
var result = response.Content.ReadAsAsync<T>().Result;
return result;
}
Controller:
string svc = appSettings.GetPeopleApiUrl;
var model = new List<Person>();
var people = Utilities.GetDataFromWebService <IEnumerable<Person>>(model, svc);
You can still have specialized methods such as GetPeople, GetPersonById by layering them on top:
PeopleModel GetPeople(...) {
return GetDataFromWebService<PeopleModel>(...);
}
No downsides, it is good that you have all boilerplate code in a shared utility method.
Well, there is definitely, better way of doing the overall implementation, but if I have to stick to the question, I would say any attempt of reducing coupling is a good step for future directions. In your situation, since you are abstracting away the responsibility of making service calls to a utility method, it would help you in the long run.
Though I would suggest that instead of having this stuffed together in Utility class you should make the connectivity it's own class, something like this
public delegate T ParseToObject<T>(string response);
public class ServiceConnector : IServiceConnector
{
public string LogoffUrl { get; set; }
public bool SupportRetry { get; set; }
private WebClient _client;
public ServiceConnector()
{
}
public T GetResponse<T>(string requestUrl, ParseToObject<T> parsingMethod)
{
string response = __getResponse(requestUrl);
return parsingMethod(response);
}
private string __getResponse(string requestUrl)
{
string serviceResponse = string.Empty;
try
{
__initializeWebClient();
Logger.Current.LogInfo(string.Format("Sending request with URL {0}", requestUrl));
serviceResponse = _client.DownloadString(requestUrl);
}
catch (Exception ex)
{
if (ex.Message != null)
{
Logger.Current.LogException(string.Format("Exception during OvidWS request {0} ", requestUrl), ex);
_client = null;
}
//Sample implementation only, you could throw the exception up based on your domain needs
}
return serviceResponse;
}
private void __initializeWebClient()
{
if (_client == null)
_client = new WebClient();
}
}
With this in place, tomorrow, let's say you want to add support to log off, support cookies, support credentials, support retries, this is the only place where you can be and comfortably make changes. Similarly if you want to use Webclient over something else, you can also do that better here.
Try with that helper:
public static class WebClientExtension
{
public static T DownloadSerializedJsonData<T>(string url) where T : new()
{
var contentType = ConfigurationManager.AppSettings["ContentType"];//content type in app config or web config
using (var webClient = new WebClient())
{
webClient.Headers.Add("Content-Type", contentType);
var jsonData = string.Empty;
try
{
jsonData = webClient.DownloadString(url);
}
catch (Exception ex)
{
throw ex;
}
return !string.IsNullOrEmpty(jsonData) ? JsonConvert.DeserializeObject<T>(jsonData) : new T();
}
}
public static T AuthorizationContentSerializedJsonData<T>(string url) where T : new()
{
string jsonData = null;
try
{
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
//ClientBase.AuthorizeRequest(httpRequest, Authorization.AccessToken);
var response = httpRequest.GetResponse();
Stream receiveStream = response.GetResponseStream();
var readStream = new StreamReader(receiveStream, Encoding.UTF8);
jsonData = readStream.ReadToEnd();
response.Close();
}
catch (Exception ex)
{
throw ex;
}
return !string.IsNullOrEmpty(jsonData) ? JsonConvert.DeserializeObject<T>(jsonData) : new T();
}
}
App confing / Web config example for content type
<add key="ContentType" value="application/hal+json; charset=UTF-8" />
I have seen similar questions asked but none that seem to help me with my issue so please bear with me.
I have a WebAPI controller method that is defined as such:
[HttpPost]
[Route("")]
public HttpResponseMessage CreateMyObject(MyObjectRequest myObject)
{
MyObject o;
try
{
o = _serviceFactory.GetInstance().CreateMyObject(myObject);
}
catch (Exception ex)
{
ex.WriteToLog();
throw ApiHelper.CreateResponseException(HttpStatusCode.InternalServerError, ex);
}
var response = Request.CreateResponse(HttpStatusCode.Created, o);
var uri = Url.Link("GetMyObjectById", new { myObjectId = o.MyObjectId.ToString() });
response.Headers.Location = new Uri(uri);
return response;
}
Say, MyObject contains two properties,
public MyObject
{
public Guid MyObjectId;
public string MyObjectName
}
A client was written to call these controller methods in a WPF application. Here is the client method that is being used:
public HttpResponseMessage CreateQuote(MyObjectRequest myObject)
{
var hashtable = new Hashtable
{
{"myObject", myObject}
};
var task = GetResponse("", hashtable);
var response = task.Result;
return response;
}
protected async Task<HttpResponseMessage> GetResponse(string path, Hashtable parameters)
{
var response = await GetAsync(BuildRequestUri(path, parameters)).ConfigureAwait(false);
return response.IsSuccessStatusCode ? response : new HttpResponseMessage();
}
protected async Task<HttpResponseMessage> GetResponse(string path)
{
return await GetResponse(path, null);
}
The controller and supporting client code was not written by me and was already in the system. I am just consuming this in the WPF application. Now, I am trying to call the controller method via the client in the application and get the MyObject from the response so that I can access the MyObjectId that has been created and set. I have tried some of the other responses to similar questions but have not even seen some of the methods that are called on the response in order to get the information. Here is the first part of the call to the client that I have in the application:
var httpResponse = ApplicationService.CreateMyObject(myObjectRequest);
The application service simply injects the client into the constructor and allows me to call the CreateMyObject method. Is there any insight that can be given to me on how I should be getting the MyObject object out of the response?
I'm still a little new to web api as well, but I'm currently working with it on a project. Give the following code a try:
MyObject myObject;
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
myObject = response.Content.ReadAsAsync<MyObject>().Result;
}
So you could theoretically change your method like this (may not be exactly what you want):
public MyObject CreateQuote(MyObjectRequest myObject)
{
var hashtable = new Hashtable
{
{"myObject", myObject}
};
var task = GetResponse("", hashtable);
var response = task.Result;
MyObject newObject;
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
newObject= response.Content.ReadAsAsync<MyObject>().Result;
}
return newObject; // instead of response
}