How to access posted server json data from client - c#

I am writing my first app using net 2.1 and angular 6.  I am able to post the json data from net 2.1 on an iis express webpage from visual studio using C#.
I am able to post data from the front end, angular/typscript, to the server. I perform calculations on the data and post the json results on the iis express server webpage. How do I get that data using angular?
Here is my angular api service file that allow me to post to the server
export class ApiService {
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('HeroesService');
}
stock: StockComponent ;
stockURL = 'https://localhost:44310/api/stock'
/** POST: */
postStock (stock) {
console.log('stock is ', stock);
this.http.post(this.stockURL, stock).subscribe(res => {
console.log(res)
})
}
getBuySellData(){
return this.http.get('https://localhost:44310/api/stock');
}
}
Here is the component file:
export class StockComponent {
stock = {}
constructor(private api: ApiService){
}
post(stock){
console.log('this is the stock ', stock)
this.api.postStock(stock)
}
Here is part of the controller in visual studio
[HttpPost]
public async Task<IActionResult> Post([FromBody]Models.Stock stock)
{
_context.Stocks.Add(stock);
await _context.SaveChangesAsync();
return Ok(stock);
}
[HttpGet]
public IEnumerable<DateCloseBuySell> GetQuote()
{
string responseString = string.Empty;

I had a similar trouble in Xamarin.Forms.
To solve it I did something like:
private const string Url = "https://localhost:44310/api/stock";
private HttpClient _client = new HttpClient();
protected async void OnGetList()
{
if (CrossConnectivity.Current.IsConnected)
{
try
{
var content = await _client.GetStringAsync(Url);
var list = JsonConvert.DeserializeObject<List<Model>>(content);
}
catch (Exception e)
{
Debug.WriteLine("", e);
}
}
}

I modified api.service.ts to
stock: StockComponent ;
stockURL = 'https://localhost:44310/api/stock'
/** POST: */
postStock (stock) {
this.http.post(this.stockURL, stock).subscribe(res => {
console.log(res)
})
}
getBuySellData(){
this.http.get(this.stockURL).subscribe(res => {
console.log(res)
})
and the component.ts to
constructor(private api: ApiService){
}
ngOnInit() {
this.api.getBuySellData()
}
post(stock){
this.api.postStock(stock)
}
I see the json data in my client console window. Thanks Chris.

Related

SignalR: notifying progress of lengthy operation from ASP.NET Core web API to Angular 7 client

EDITED: see at the bottom
I'm new to SignalR and trying to implement with it a simple scenario with Angular7 client using this library, and ASP.NET Core web API. All what I need is to use SignalR to notify the client about the progress of some lengthy operations in methods of the API controllers.
After a number of attempts, I got to a point where apparently the connection is established, but then when the long task starts running and sending messages, my client does not seem to receive anything, nor any traffic appears in web sockets (Chrome F12 - Network - WS).
I post here the details, which might also be useful to other newcomers (full source code at https://1drv.ms/u/s!AsHCfliT740PkZh4cHY3r7I8f-VQiQ). Probably I'm just making some obvious error, yet in the docs and googling around I could not find a code fragment essentially different from mine. Could anyone give a hint?
My start point for the server side was https://msdn.microsoft.com/en-us/magazine/mt846469.aspx, plus the docs at https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-2.2. I tried to create a dummy experimental solution with that.
My code snippets in form of a recipe follow.
(A) Server Side
1.create a new ASP.NET core web API app. No authentication or Docker, just to keep it minimal.
2.add the NuGet package Microsoft.AspNetCore.SignalR.
3.at Startup.cs, ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
// CORS
services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyMethod()
.AllowAnyHeader()
// https://github.com/aspnet/SignalR/issues/2110 for AllowCredentials
.AllowCredentials()
.WithOrigins("http://localhost:4200");
}));
// SignalR
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
and the corresponding Configure method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
// CORS
app.UseCors("CorsPolicy");
// SignalR: add to the API at route "/progress"
app.UseSignalR(routes =>
{
routes.MapHub<ProgressHub>("/progress");
});
app.UseHttpsRedirection();
app.UseMvc();
}
4.add a ProgressHub class, which just derives from Hub:
public class ProgressHub : Hub
{
}
5.add a TaskController with a method to start some lengthy operation:
[Route("api/task")]
[ApiController]
public class TaskController : ControllerBase
{
private readonly IHubContext<ProgressHub> _progressHubContext;
public TaskController(IHubContext<ProgressHub> progressHubContext)
{
_progressHubContext = progressHubContext;
}
[HttpGet("lengthy")]
public async Task<IActionResult> Lengthy([Bind(Prefix = "id")] string connectionId)
{
await _progressHubContext
.Clients
.Client(connectionId)
.SendAsync("taskStarted");
for (int i = 0; i < 100; i++)
{
Thread.Sleep(500);
Debug.WriteLine($"progress={i}");
await _progressHubContext
.Clients
.Client(connectionId)
.SendAsync("taskProgressChanged", i);
}
await _progressHubContext
.Clients
.Client(connectionId)
.SendAsync("taskEnded");
return Ok();
}
}
(B) Client Side
1.create a new Angular7 CLI app (without routing, just to keep it simple).
2.npm install #aspnet/signalr --save.
3.my app.component code:
import { Component, OnInit } from '#angular/core';
import { HubConnectionBuilder, HubConnection, LogLevel } from '#aspnet/signalr';
import { TaskService } from './services/task.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
private _connection: HubConnection;
public messages: string[];
constructor(private _taskService: TaskService) {
this.messages = [];
}
ngOnInit(): void {
// https://codingblast.com/asp-net-core-signalr-chat-angular/
this._connection = new HubConnectionBuilder()
.configureLogging(LogLevel.Debug)
.withUrl("http://localhost:44348/signalr/progress")
.build();
this._connection.on("taskStarted", data => {
console.log(data);
});
this._connection.on("taskProgressChanged", data => {
console.log(data);
this.messages.push(data);
});
this._connection.on("taskEnded", data => {
console.log(data);
});
this._connection
.start()
.then(() => console.log('Connection started!'))
.catch(err => console.error('Error while establishing connection: ' + err));
}
public startJob() {
this.messages = [];
this._taskService.startJob('zeus').subscribe(
() => {
console.log('Started');
},
error => {
console.error(error);
}
);
}
}
Its minimalist HTML template:
<h2>Test</h2>
<button type="button" (click)="startJob()">start</button>
<div>
<p *ngFor="let m of messages">{{m}}</p>
</div>
The task service in the above code is just a wrapper for a function which calls HttpClient's get<any>('https://localhost:44348/api/task/lengthy?id=' + id).
EDIT 1
After some more experimenting, I came with these changes:
use .withUrl('https://localhost:44348/progress') as suggested. It seems that now it no more triggers 404. Note the change: I replaced http with https.
do not make the API method async as it seems that the await are not required (i.e. set the return type to IActionResult and remove async and await).
With these changes, I can now see the expected log messages on the client side (Chrome F12). Looking at them, it seems that the connection gets bound to a generated ID k2Swgcy31gjumKtTWSlMLw:
Utils.js:214 [2019-02-28T20:11:48.978Z] Debug: Starting HubConnection.
Utils.js:214 [2019-02-28T20:11:48.987Z] Debug: Starting connection with transfer format 'Text'.
Utils.js:214 [2019-02-28T20:11:48.988Z] Debug: Sending negotiation request: https://localhost:44348/progress/negotiate.
core.js:16828 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
Utils.js:214 [2019-02-28T20:11:49.237Z] Debug: Selecting transport 'WebSockets'.
Utils.js:210 [2019-02-28T20:11:49.377Z] Information: WebSocket connected to wss://localhost:44348/progress?id=k2Swgcy31gjumKtTWSlMLw.
Utils.js:214 [2019-02-28T20:11:49.378Z] Debug: Sending handshake request.
Utils.js:210 [2019-02-28T20:11:49.380Z] Information: Using HubProtocol 'json'.
Utils.js:214 [2019-02-28T20:11:49.533Z] Debug: Server handshake complete.
app.component.ts:39 Connection started!
app.component.ts:47 Task service succeeded
So, it might be the case that I get no notification because my client ID does not match the ID assigned by SignalR (from the paper quoted above I had the impression that it was my duty to provide an ID, given that it is an argument of the API controller). Yet, I cannot see any available method or property in the connection prototype allowing me to retrieve this ID, so that I can pass it to the server when launching the lengthy job. Could this be the reason of my issue? If this is so, there should be a way of getting the ID (or setting it from the client side). What do you think?
It seems I've finally found it. The issue was probably caused by the wrong ID, so I started looking for a solution. A post (https://github.com/aspnet/SignalR/issues/2200) guided me to the usage of groups, which seems the recommended solution in these cases. So, I changed my hub so that it automatically assign the current connection ID to a "progress" group:
public sealed class ProgressHub : Hub
{
public const string GROUP_NAME = "progress";
public override Task OnConnectedAsync()
{
// https://github.com/aspnet/SignalR/issues/2200
// https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/working-with-groups
return Groups.AddToGroupAsync(Context.ConnectionId, "progress");
}
}
Now, my API controller method is:
[HttpGet("lengthy")]
public async Task<IActionResult> Lengthy()
{
await _progressHubContext
.Clients
.Group(ProgressHub.GROUP_NAME)
.SendAsync("taskStarted");
for (int i = 0; i < 100; i++)
{
Thread.Sleep(200);
Debug.WriteLine($"progress={i + 1}");
await _progressHubContext
.Clients
.Group(ProgressHub.GROUP_NAME)
.SendAsync("taskProgressChanged", i + 1);
}
await _progressHubContext
.Clients
.Group(ProgressHub.GROUP_NAME)
.SendAsync("taskEnded");
return Ok();
}
And of course I updated the client code accordingly, so that it does no more have to send an ID when invoking the API method.
Full demo repository available at https://github.com/Myrmex/signalr-notify-progress.
You set the route for the hub as /progress, but then you're attempting to connect to /signalr/progress, which is going to be a 404. If you open the developer console, you should have an connection error there telling you as much.
Just wanted to add that OP was on the right track with the connection ID.
I send it along optionally in the form data.
I'm just reporting progress while uploading to AWS and I handle with SignalR like this:
Controller
[HttpPost("MyPostRoute")]
public async Task<ActionResult> UploadFiles([FromForm] List<IFormFile> files, [FromForm] string? connectionId)
{
await _logic.UploadFiles(files, connectionId);
return Ok();
}
Logic
public async Task<bool> UploadFiles(List<IFormFile> files, string? connectionId)
{
foreach (var file in files)
{
Guid fileGuid = Guid.NewGuid();
string extension = Path.GetExtension(file.FileName);
using (var transferUtility = new TransferUtility(_awsClient))
{
var request = new TransferUtilityUploadRequest()
{
BucketName = _configuration["AwsBucket"],
Key = fileGuid + extension,
InputStream = file.OpenReadStream()
};
if (connectionId != null)
{
AwsFileProgress progress = new()
{
ConnectionId = connectionId,
FileName = file.FileName
};
request.UploadProgressEvent += (sender, e) => Request_UploadProgressEvent(sender, e, progress);
}
await transferUtility.UploadAsync(request);
}
}
return true;
}
private async void Request_UploadProgressEvent(object? sender, UploadProgressArgs e, AwsFileProgress progress)
{
progress.ProgressPercent = e.PercentDone;
await _hub.Clients.Client(progress.ConnectionId).SendAsync("AWSProgress", progress);
}
I made a model for the progress stuff:
public class AwsFileProgress
{
public string ConnectionId { get; set; }
public string FileName { get; set; }
public int ProgressPercent { get; set; } = 0;
}
And finally, the front-end:
import { Injectable } from '#angular/core';
import * as signalR from "#microsoft/signalr";
import { environment } from "#environment";
import { AwsFileProgress } from "#models/signalr/awsFileProgress";
#Injectable({
providedIn: 'root',
})
export class AwsSignalRService {
private hubConnection!: signalR.HubConnection
public data!: AwsFileProgress;
public startConnection = () => {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${environment.signalRhubRoot}/awsprogresshub`)
.build();
this.hubConnection
.start()
.then(() => { console.log('AWS SignalR Service Connection started') })
.catch(err => console.log('Error while starting AWS SignalR Service WebSocket: ' + err))
}
/////////////////////////////////////////////////////////
//This is all you have to do to get the connection ID:
public getConnectionId() : string | null {
return this.hubConnection.connectionId;
}
/////////////////////////////////////////////////////////
public addAwsProgressListener = () => {
this.hubConnection.on('AWSProgress', (awsFileProgress : AwsFileProgress) => {
this.data = awsFileProgress;
console.log(awsFileProgress.progressPercent);
});
}
}
Then the actual component it's injected into:
import { AwsSignalRService } from "#shared/services/aws-signalr-service";
#Component({
selector: 'settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss'],
})
export class SettingsComponent implements OnInit {
constructor(
private awsSignalRService: AwsSignalRService
) {
awsSignalRService.startConnection();
awsSignalRService.addAwsProgressListener();
}
^ Whatever is in our progress listener is handled here.
Making the request (and reporting client-side upload progress) is handled like this.
Note that I just use a basic (change) handler on a file input (<input type="file" (change)="fileUploadTest($event)"/>)
fileUploadTest(e: any) {
const formData = new FormData();
var cId = this.awsSignalRService.getConnectionId();
for(let file of e.target.files as File[]) {
formData.append('files', file, file.name);
};
if(cId != null)
formData.append('connectionId',cId);
const url: string = `${environment.ApiRoot}/MyPostRoute`;
this.http.post<any>(url,formData, {
reportProgress: true,
observe: 'events'
}).subscribe({
next: (response) => console.log(response),
error: (error) => console.log(error)
});
}
And the results in console of my API uploading data to AWS:

My data does not pass through to controller from Typescript view? I am using angular 5 .net core apllication 2.0

Here is my code for Method in TypeScript
Ive been trying to pass an number[] array to the controller to send to a quickbooks api but all i really need right now is to get the values into the controller,
This is been done in Angular 5 .net core 2.0 latest version
The data hits the Post Method with no error and i have breakpoints everywhere it never reaches the controller.
import { Injectable } from '#angular/core';
import { Customer } from '../models/customer';
import { Vendor } from '../models/vendor';
import { Item } from '../models/item';
import { Invoice } from '../models/invoice';
import { CreditNote } from '../models/creditNote';
import { PPO } from '../models/ppo';
import { PO } from '../models/po';
import { AppSettings } from '../models/appSettings';
import { Http, Response, Headers, RequestOptions, RequestMethod, URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { MsgResult } from '../models/msgResult';
import { Router, ActivatedRoute } from '#angular/router';
import { isPlatformBrowser, isPlatformServer } from '#angular/common';
#Injectable()
export class SyncDataService {
errorMessage: string = "";
baseURL: string = 'http://localhost:56199/api';
constructor(private _http: Http, private route: ActivatedRoute, private router: Router) {}
syncCustomers(ids: Array<number>) {
var headers = new Headers();
headers.append('Content-Type', 'application/json; charset=utf-8');
var localStorage1 = localStorage.getItem('access_token');
if (localSt
orage1 != undefined) {
var token = JSON.parse(localStorage1);
//headers.append('Authorization', 'bearer ' + token);
//return this._http.post(this.baseURL + '/customer', ids, options)
// .map((response: Response) => <string>response.json())
// .catch(err => {
// return this.handleError(err);
// });
var stringids = JSON.stringify({ customerIDs: ids });
this._http.post(this.baseURL + '/customer/PostCust',
stringids).subscribe(result => result.json()), err => {
return this.handleError(err);
}
}
}
}
Here is my controller
[Route("api/[controller]")]
public class CustomerController : Controller
{
private readonly SyncDbContext _dbContext;
public CustomerController(SyncDbContext dbContext)
{
_dbContext = dbContext;
}
[HttpGet]
public List<Customer> Get()
{
return new SyncDataManager().GetCustomers();
}
[HttpPost("[action]")]
[AllowAnonymous]
public JsonResult PostCust([FromBody]int[] customerIDs)
{
// call quicbooks api and pass them the customers
// once quickbooks verifys the customer and sends us back a reference
// pass the quickbooks customer to SyncDataManager
var sync = new SyncDataManager();
var results = sync.UpdateCustomers(customerIDs);
var failedResults = results.Where(m => m.Success == false).ToList();
if(failedResults.Count == 0)
{
var json = new JsonResult("Updated Successfully");
json.StatusCode = 200;
return json;
}
else
{
var error = new StringBuilder();
foreach (var errorMessage in failedResults)
{
//string output = errorMessage.ErrorMessage.Substring(errorMessage.ErrorMessage.IndexOf('.') + 1);
string output = errorMessage.ErrorMessage;
error.AppendLine(output);
}
var json = new JsonResult(error.ToString());
json.StatusCode = 400;
return json;
}
}
There is no error messages and when i use break points on my controller, It does not hit the break points, been at it for 3 days no break through Please help
try in your Controller
[Route("api/[controller]/[action]")] //<--include action
public class CustomerController : Controller
{
...
[HttpGet,ActionName("Get")] //<--I don't know if it's necesary
public List<Customer> Get() {..}
[HttpPost, ActionName("PostCust")] //<--give there the "actionName
[AllowAnonymous]
public JsonResult PostCust([FromBody]int[] customerIDs){...}
}
this._http.post(this.baseURL + '/customer/PostCust',
this.customerIDs).subscribe((data:Response) => { this.resu = (data.json() as string) },
error => {
alert(error.json());
},
() => {
alert("Completed");
} else {
this.RefreshCustomers();
}
});
this.resu is my results variable
and no headers or casts for this.customerIDs this worked for me

ASP.NET Core 2.0 Web API Receiving/Sending Json requests from ionic 3

I have an ASP.NET Core 2.0 Web API Integrated with ionic 3.
I'm having problems receiving JSON data sent from ionic 3 App, Here is sample code:-
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { AlertController, LoadingController } from 'ionic-angular';
import { FCM } from '#ionic-native/fcm';
#Injectable()
export class ServerProvider {
private baseurl = "http://localhost:9681/api";
private api: String[] = new Array();
public loader: any;
constructor(public fcm: FCM, public http: Http, public alertCtrl:
AlertController, public loadingCtrl: LoadingController) {
this.api['auth'] = 'Authentication';
this.api['agency'] = 'Agencies';
this.api['user'] = 'Users';
this.api['route'] = 'Routes';
this.api['token'] = 'Tokens';
this.api['notification'] = 'Notifications';
this.api['salepoint'] = 'Salepoints';
}
ServerRequest(api, request, data) {
return new Promise((resolve) => {
let headers = new Headers();
headers.append('Content-Type', 'application/json; charset=UTF-8');
this.http.get(this.baseurl + "/" + this.api[api] + "/", {headers: headers}).map(res => res.json()).subscribe((result) => {
resolve(result);
console.log(result);
}, (error) => {
console.log(error); this.CreateAlert("Error", error, [
{
text: 'Close',
handler: () => {
this.loader.dismiss();
}
}
]);
}, () => {
this.loader.dismiss();
});
});
}
Backend:-
[Route("api/Authentication")]
public class AuthenticationController : Controller
{
IConfiguration _configuration;
public AuthenticationController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public JsonResult GetUser(JsonResult json)
{
AgencyUsers agencyusers = new AgencyUsers(_configuration);
return Json(agencyusers.GetUser(json));
}
}
I receive the following error:-
An unhandled exception occurred while processing the request.
InvalidOperationException: Could not create an instance of type
'Microsoft.AspNetCore.Mvc.JsonResult'. Model bound complex types must
not be abstract or value types and must have a parameterless
constructor.
What is the correct way to receive (serialize and deserialize JSON) and send back JSON (data or errors)?
After a lot of digging and modifications, I have finally got the API to work fine.
In case someone ran into a problem similar to mine, Here what I did:-
At Ionic, I have changed the HTTP request from GET to POST.
ServerRequest(api, request, data) {
return new Promise((resolve) => {
let headers = new Headers();
headers.append('Content-Type', 'application/json; charset=UTF-8');
this.http.post(this.baseurl + "/" + this.api[api] + "/" + request, JSON.stringify(data),{headers:headers}).map(res => res.json()).subscribe((result) => { ... });}
At Backend, Used newtonsoft (JObject) Which saved me a lot of head that JsonResult causes, Then Changed Method type to IActionResult.
[HttpPost("GetAgencyUser")]
public IActionResult GetAgencyUser([FromBody]JObject request)
{
try
{
if (request["id"] == null)
{
return Ok("id is not defined or incorrect JSON format");
}
AgencyUsersMethods agencyusers = new AgencyUsersMethods(_configuration);
var result = agencyusers.GetAgencyUser(request);
if (result == null)
{
return Ok("User not Found");
}
else
{
return Ok(result);
}
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}

How to consume ASP Rest web Api in Xamarin forms?

I have created a REST Api in ASP.Net web form. I can read and write data from MySql database using the API (I tested the Api using chrome's REST Client extension). Now I am trying to consume the Rest Api in my cross platform xamarin forms. I just added a button in my app and see whether it can retrieve data if I click the button. I inserted a breakpoint at the var Json to see whether I'm getting any data. But I am not able to retrieve it. I am running the Web Api in localhost. I run the app in VS Android emulator. Please guide me on how to properly consume the REST web service. Thank you.
Web Api
namespace WorkAppApi.Controllers
{
public class MachinesController : ApiController
{
// GET: api/Machines
public List<machines> Get()
{
DBConn db = new DBConn();
return db.getMachineList();
}
// GET: api/Machines/5
public machines Get(long id)
{
DBConn db = new DBConn();
machines m = db.getMachine(id);
return m;
}
// POST: api/Machines
public HttpResponseMessage Post([FromBody]machines value)
{
DBConn db = new DBConn();
long id;
id = db.addMachine(value);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created);
response.Headers.Location = new Uri(Request.RequestUri, String.Format("machines/{0}", id));
return response;
}
// PUT: api/Machines/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE: api/Machines/5
public void Delete(int id)
{
}
}
}
Function submit button.
namespace WorkApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestPage : ContentPage
{
private string Uri = "http://192.168.0.124:59547/api/Machines/";
public TestPage ()
{
InitializeComponent ();
check();
}
private async Task submit(object sender, EventArgs e)
{
var httpClient = new HttpClient();
var json = await httpClient.GetAsync(Uri);
}
}
}
this would be my answer:
namespace WorkApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestPage : ContentPage
{
private string Uri = "http://192.168.0.124:59547/api/";
List<Machine> machines;
public TestPage ()
{
InitializeComponent ();
check();
}
private async Task submit(object sender, EventArgs e)
{
var httpClient = new HttpClient();
httpClient.BaseAddress = Uri // I have changed the Uri variabele, you should extend this class and give it the same base address in the constructor.
var resp= await httpClient.GetAsync("Machines");
if (resp.Result.IsSuccessStatusCode)
{
var repStr = resp.Result.Content.ReadAsStringAsync();
machines= JsonConvert.DeserializeObject<List<Machine>>(repStr.Result.ToString());
}
}
}
}

Call web API from client app

I used to use ASMX web services, however have since read (and been told) that a better way to request data from a client etc is to use web API's with MVC.
I have created an MVC 4 web api application and getting to grips with how it works.
Currently I have a single public string in my valuesControllers -
public class ValuesController : ApiController
{
// GET api/values/5
public string Get(int id)
{
return "value";
}
}
And I am currently trying to call this in my client like this -
class Product
{
public string value { get; set; }
}
protected void Button2_Click(object sender, EventArgs e)
{
RunAsync().Wait();
}
static async Task RunAsync()
{
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://localhost:12345/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
HttpResponseMessage response = await client.GetAsync("api/values/5");
if (response.IsSuccessStatusCode)
{
Product product = await response.Content.ReadAsAsync<Product>();
Console.WriteLine("{0}", product.value);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
}
On debugging I can step through the request and enter the web API code successfully however on the line -
Product product = await response.Content.ReadAsAsync<Product>();
This fails and enters my catch with the exception -
Error converting value "value" to type 'myDemo.Home+Product'. Path '', line 1, position 7.
Why is this?
Why is this?
Because from your controller action you are returning a string, not a Product which are 2 quite different types:
public string Get(int id)
{
return "value";
}
so make sure that you are consistently reading the value on the client:
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsAsync<string>();
Console.WriteLine("{0}", result);
}
Of course if you modified your API controller action to return a Product:
public Product Get(int id)
{
Product product = ... go fetch the product from the identifier
return product;
}
your client code would work as expected.

Categories

Resources