async calls using HttpClient on MVC4 - asp.net-mvc

I'm playing a little bit with this new technology in .net 4.5, I would like to check the code for this call and how should I control the errors or the response of my async call.
The call is working perfectly, I need full control of possible errors returned from my service.
this is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
namespace TwitterClientMVC.Controllers
{
public class Tweets
{
public Tweet[] results;
}
public class Tweet
{
[JsonProperty("from_user")]
public string UserName { get; set; }
[JsonProperty("text")]
public string TweetText { get; set; }
}
}
public async Task<ActionResult> Index()
{
Tweets model = null;
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://mywebapiservice");
response.EnsureSuccessStatusCode();
model = JsonConvert.DeserializeObject<Tweets>(response.Content.ReadAsStringAsync().Result);
return View(model.results);
}
Is this the better way to do it? or I'm missing something?
Thanks
I refactor it, is this method async as well?
public async Task<ActionResult> Index()
{
Tweets model = null;
using (HttpClient httpclient = new HttpClient())
{
model = JsonConvert.DeserializeObject<Tweets>(
await httpclient.GetStringAsync("http://search.twitter.com/search.json?q=pluralsight")
);
}
return View(model.results);
}

Is this the better way to do it?
The response.EnsureSuccessStatusCode(); will throw an exception if the status code returned by your remote service is different than 2xx. So you might want to use the IsSuccessStatusCode property instead if you want to handle the error yourself:
public async Task<ActionResult> Index()
{
using (HttpClient client = new HttpClient())
{
var response = await client.GetAsync("http://mywebapiservice");
string content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var model = JsonConvert.DeserializeObject<Tweets>(content);
return View(model.results);
}
// an error occurred => here you could log the content returned by the remote server
return Content("An error occurred: " + content);
}
}

Related

Stored procedure ADO.NET .NET Core Web API

I am building a Web API in ASP.NET Core, I am using stored procedures to be able to handle more complex queries, which with the Entity Framework is too complicated for me, I am using ADO.NET to make this connection.
I have managed to connect to a stored procedure and use the get and post methods, the point is that I don't know how to do it in order to call the other stored procedures and map a route to interact via get or post in the same project. I have only been able to do one, and I don't think it would be more convenient to create a Web API for each function that complies with a stored procedure.
My project is made up of three folders called Controller, Data, Models.
Within Models is the Value class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ASPNETCore_StoredProcs.Models
{
public class Value
{
public int Id { get; set; }
public int Value1 { get; set; }
public string Value2 { get; set; }
}
}
Data folder has a class called ValueRepository
using ASPNETCore_StoredProcs.Models;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;
namespace ASPNETCore_StoredProcs.Data
{
public class ValuesRepository
{
private readonly string _connectionString;
public ValuesRepository(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("defaultConnection");
}
public async Task<List<Value>> GetAll()
{
using (SqlConnection sql = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand("GetAllValues", sql))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
var response = new List<Value>();
await sql.OpenAsync();
using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
response.Add(MapToValue(reader));
}
}
return response;
}
}
}
private Value MapToValue(SqlDataReader reader)
{
return new Value()
{
Id = (int)reader["Id"],
Value1 = (int)reader["Value1"],
Value2 = reader["Value2"].ToString()
};
}
public async Task<Value> GetById(int Id)
{
using (SqlConnection sql = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand("GetValueById", sql))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#Id", Id));
Value response = null;
await sql.OpenAsync();
using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
response = MapToValue(reader);
}
}
return response;
}
}
}
public async Task Insert(Value value)
{
using (SqlConnection sql = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand("InsertValue", sql))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#value1", value.Value1));
cmd.Parameters.Add(new SqlParameter("#value2", value.Value2));
await sql.OpenAsync();
await cmd.ExecuteNonQueryAsync();
return;
}
}
}
public async Task DeleteById(int Id)
{
using (SqlConnection sql = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand("DeleteValue", sql))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#Id", Id));
await sql.OpenAsync();
await cmd.ExecuteNonQueryAsync();
return;
}
}
}
}
}
and finally I have a controller class called ValuesController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ASPNETCore_StoredProcs.Data;
using ASPNETCore_StoredProcs.Models;
using Microsoft.AspNetCore.Mvc;
namespace ASPNETCore_StoredProcs.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly ValuesRepository _repository;
public ValuesController(ValuesRepository repository)
{
this._repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
// GET api/values
[HttpGet]
public async Task<ActionResult<IEnumerable<Value>>> Get()
{
return await _repository.GetAll();
}
// GET api/values/5
[HttpGet("{id}")]
public async Task<ActionResult<Value>> Get(int id)
{
var response = await _repository.GetById(id);
if (response == null) { return NotFound(); }
return response;
}
// POST api/values
[HttpPost]
public async Task Post([FromBody] Value value)
{
await _repository.Insert(value);
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public async Task Delete(int id)
{
await _repository.DeleteById(id);
}
}
}
This is my startup class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ASPNETCore_StoredProcs.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace ASPNETCore_StoredProcs
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ValuesRepository>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
}
I appreciate if you can help me or if it is how I think I should create an API for each procedure that is performed thanks

Calling SignalR Hub method from client locks Xamarin android App

I finally got a SignalR Hub to work using the Microsoft.AspNet.SignalR vice the Microsoft.AspNetCore.SignalR, I was unable to get the Microsoft.AspNetCore.SignalR, no idea why. But I did get the other one to work. I am able to connect, link clients to connection id's using OnConnect and removing them using OnDisconnect. My Hub code is:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.SignalR;
using SignalrHub;
namespace SignalRChat
{
public class ChatHub : Hub
{
private static readonly List<User> Users = new List<User>();
public override Task OnConnected()
{
// string userName = Context.User.Identity.Name;
string userName = Context.QueryString["username"];
string org= Context.QueryString["organization"];
string dept = Context.QueryString["dept"];
string team = Context.QueryString["team"];
string firstname = Context.QueryString["firstname"];
string lastname = Context.QueryString["lastname"];
string connectionId = this.Context.ConnectionId;
// for now I just capture username and connection Id
var user = new User();
user.Name = userName;
user.ConnectionIds = connectionId;
try
{
Users.Add(user);
}
catch (Exception ex)
{
var msg = ex.Message;
}
// TODO: Broadcast the connected user
// send list of connected users to client
Send("Welcome " + userName, "Connected users are:");
foreach (var display in Users)
{
Send("",display.Name.ToString());
}
return base.OnConnected();
}
public override Task OnDisconnected(bool stopped)
{
string userName = Context.User.Identity.Name;
string connectionId = Context.ConnectionId;
var item = Users.Find(x => x.ConnectionIds == connectionId);
Users.Remove(item);
return base.OnDisconnected(true);
}
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
}
public List<String> GetConnectedUsers()
{
List<string> UserNames = new List<string>();
foreach (var ConnectedUser in Users)
{
UserNames.Add(ConnectedUser.Name);
}
return UserNames;
}
}
}
Everything works fine except when I call GetConnectedUsers(), when I call that from the client with this code ConnecteduserList = client.ConnectedUsers(); the app locks up, eg; the hub never returns from that method. Clearly I'm missing something. Can anyone tell me what?
The client code in the app is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
namespace ChatClient.Shared
{
class Client
{
//public string username;
private readonly string _platform;
private readonly HubConnection _connection;
private readonly IHubProxy _proxy;
public event EventHandler<string> OnMessageReceived;
public Client(string platform, string username)
{
string _username = "username=" + username;
_platform = platform;
_connection = new HubConnection("https://MyApp.com/SignalRhub", _username);
_proxy = _connection.CreateHubProxy("chathub");
}
public async Task Connect()
{
await _connection.Start(); _proxy.On("broadcastMessage", (string platform, string message) =>
{
if (OnMessageReceived != null)
OnMessageReceived(this, string.Format("{0}: {1}", platform, message));
});
Send("Connected");
}
public List<string> ConnectedUsers()
{
List<string> Users = new List<string>();
// Locks up when this line is esecuted. The server log has nothing in it.
Users = _proxy.Invoke<List<string>>("GetConnectedUsers").Result;
return Users;
}
public Task Send(string message)
{
return _proxy.Invoke("Send", _platform, message);
}
}
}
Thanks to David Fowler over at GitHub who provided the link to this document (https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#avoid-using-taskresult-and-taskwait), I was able to get this to work by changing my code as follows:
On the client:
From:
public List<string> ConnectedUsers()
{
// Hangs on this line
List<string> Users = _proxy.Invoke<List<string>>("getConnectedUsers").Result;
return Users;
}
To:
public async Task <List<string>> ConnectedUsers()
{
List<string> Users = await _proxy.Invoke<List<string>>("getConnectedUsers");
return Users;
}
The call to the ConnectedUsers function in Client.cs was changed as well:
From:
List<string> userList = client.ConnectedUsers();
To:
List<string> userList = await client.ConnectedUsers();
No changes to the hub code were necessary.

Asynchronous request not working after separating data retrieval code

I am trying to display some results after querying a webapi as below -
public async Task<ActionResult> Get()
{
string _address = "someurl";
string results = null;
HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));
HttpResponseMessage responseTask = await client.GetAsync(_address);
if (responseTask.IsSuccessStatusCode)
{
results = await responseTask.Content.ReadAsStringAsync();
}
ResultModel model = JsonConvert.DeserializeObject<ResultModel>(results);
return View(model);
}
This code works fine and I am able to read the results from "someurl" url. Now, when I refator the code as below (by moving the async data retrieval to another function), it stops working. It forever takes to query and does not return any result. Is this because of some deadlock or am I not using async correctly.
public ActionResult Get()
{
string _address = "someurl";
Task<string> results = HttpClientService.HttpClientService.GetRequest(_address);
IEnumerable<ResultModel> model = JsonConvert.DeserializeObject<IEnumerable<ResultModel>>(results.Result);
return View(model);
}
public static class HttpClientService
{
public static async Task<string> GetRequest(string Url)
{
HttpClient client = new HttpClient(new OAuthMessageHandler(new HttpClientHandler()));
HttpResponseMessage responseTask = await client.GetAsync(Url);
if (responseTask.IsSuccessStatusCode)
{
return await responseTask.Content.ReadAsStringAsync();
}
else
{
return "Sorry buddy, cannot retrieve the requested data!";
}
}
}
Please let me know what am I doing wrong here. I am new to Async implementation.
You should await the GetRequest method. Otherwise you are defeating the purpose of async processing which is to release the thread so it can do other work. In this case you are still blocking the thread when you ask for a result via results.Result.
public async Task<ActionResult> Get()
{
string _address = "someurl";
string results = await HttpClientService.HttpClientService.GetRequest(_address);
IEnumerable<ResultModel> model = JsonConvert.DeserializeObject<IEnumerable<ResultModel>>(results);
return View(model);
}
Frankly I am not sure why your code is not returning but even if it was working correctly it would be pointless to do async requests in this way.

web api call from code behind

i am very new to mvc web api
I have crated a web api Post method which takes an object type "Bag" and return a HTMLString the code is as shown bellow
public HtmlString PostBag(Bag bagofItem)
{
return Utility.PostBagDiscountedItem(bagofItem);
}
now from my web site i wanted to call the API method PostBag from the controller PostBag()
and i am do not know how to and appreciate if some one can show me how to do this
what i have got in my web application is as bellow.
public class HomeController : Controller
{
private Bag _bag = new Bag();
private string uri = "http://localhost:54460/";
public ActionResult PostBag()
{
// would some one show me how to POST the _bag to API Method PostBag()
return View();
}
public class Bag
{
private static List<Product> _bag { get; set; }
public List<Product> GetBag ()
{
if (_bag == null)
_bag = new List<Product>();
return _bag;
}
}
Try this:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:54460/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(_bag);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine("Error with feed");
}
}

Issues with MultipartFormDataStreamProvider

I'm trying to follow this tutorial, and I'm realizing that even if I copy and past his code, I'm getting two compile errors in my ApiController.
IEnumerable<HttpContent> bodyparts = Request.Content.ReadAsMultipartAsync(streamProvider);
This tells me that the return of ReadAsMultipartAsync can't be cast to an IEnumerable of HttpContent.
IDictionary<string, string> bodypartFiles = streamProvider.BodyPartFileNames;
And this is telling me that BodyPartFileNames doesn't exist in streamProvider, which seems contrary to the tutorial as well as several other blog posts and StackOverflow questions I've seen.
Anyone have any idea what the deal is?
Full file:
using AsyncFileUpload.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
namespace AsyncFileUpload.Controllers
{
public class UploadingController : ApiController
{
private const string PATH = "C:\\_projects\\learning";
[HttpPost]
public async Task<IList<FileDesc>> Post()
{
List<FileDesc> result = new List<FileDesc>();
if (Request.Content.IsMimeMultipartContent())
{
try
{
if (!Directory.Exists(PATH))
{
Directory.CreateDirectory(PATH);
}
MultipartFormDataStreamProvider streamProvider =
new MultipartFormDataStreamProvider(PATH);
IEnumerable<HttpContent> bodyparts = Request.Content.ReadAsMultipartAsync(streamProvider);
IDictionary<string, string> bodypartFiles = streamProvider.BodyPartFileNames;
IList<string> newFiles = new List<string>();
foreach (var item in bodypartFiles)
{
var newName = string.Empty;
var file = new FileInfo(item.Value);
if (item.Key.Contains("\""))
{
newName = Path.Combine(file.Directory.ToString(),
item.Key.Substring(1, item.Key.Length - 2));
}
else
{
newName = Path.Combine(file.Directory.ToString(), item.Key);
}
File.Move(file.FullName, newName);
newFiles.Add(newName);
}
var uploadedFiles = newFiles.Select(i =>
{
var fi = new FileInfo(i);
return new FileDesc(fi.Name, fi.FullName, fi.Length);
}).ToList();
result.AddRange(uploadedFiles);
}
catch (Exception e)
{
// NOOP
}
}
return result;
}
}
}
ReadAsMultipartAsync returns a Task<> object. Take the .Result property (which blocks) or use the await keyword to wait on the task (preferable).
BodyPartFileNames was changed in the RTM release, now use the FileData property.
See: http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2

Resources