I wanted to try out this example of a self-hosted webservice (originally written in WCF WebApi), but using the new ASP.NET WebAPI (which is the descendant of WCF WebApi).
using System;
using System.Net.Http;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using Microsoft.ApplicationServer.Http;
namespace SampleApi {
class Program {
static void Main(string[] args) {
var host = new HttpServiceHost(typeof (ApiService), "http://localhost:9000");
host.Open();
Console.WriteLine("Browse to http://localhost:9000");
Console.Read();
}
}
[ServiceContract]
public class ApiService {
[WebGet(UriTemplate = "")]
public HttpResponseMessage GetHome() {
return new HttpResponseMessage() {
Content = new StringContent("Welcome Home", Encoding.UTF8, "text/plain")
};
}
}
}
However, either I haven't NuGotten the right package, or HttpServiceHost is AWOL. (I chose the 'self hosting' variant).
What am I missing?
Please refer to this article for self-hosting:
Self-Host a Web API (C#)
The complete rewritten code for your example would be as follows:
class Program {
static void Main(string[] args) {
var config = new HttpSelfHostConfiguration("http://localhost:9000");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
using (HttpSelfHostServer server = new HttpSelfHostServer(config)) {
server.OpenAsync().Wait();
Console.WriteLine("Browse to http://localhost:9000/api/service");
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
public class ServiceController : ApiController {
public HttpResponseMessage GetHome() {
return new HttpResponseMessage() {
Content = new StringContent("Welcome Home", Encoding.UTF8, "text/plain")
};
}
}
Hope this helps.
Related
My program is for Self hosting a Web API in a Windows Application.
As I dont have much experience in web servie, I request someone's help to fix the problem.
I could make a console application successfully.
But when I change it in to Windows application, my IDE goes stuck with Error "The application is in Break Mode".
Console Program;
using System.Web.Http;
using System.Web.Http.SelfHost;
Main Function:
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit."); // Removed in Win Form
Console.ReadLine(); // Removed in Win Form
}
API Controller Class; I need to receive data here from "FromBody" attribute.
public class FieldsController : ApiController
{
[HttpPost]
public void PostAction([FromBody] Field model)
{
int patientID;
string name;
string age;
patientID = model.patientID;
name = model.patientName;
age = model.patientAge;
}
}
Can you put your error in more detail ?
I have also done in similar way and my one is working.
In the solution of the project I added a new class libraray type project for the webapi.
From the main windowsForm application I am intatiating the webapi.
The webapi project is as below:
using System;
using System.ServiceModel;
using System.Web.Http;
using System.Web.Http.SelfHost;
namespace MYWebAPI
{
public class WebApiProgram : IDisposable
{
private string URL = "http://localhost:1234/";
private HttpSelfHostServer server;
public WebApiProgram()
{
}
public WebApiProgram(string url)
{
this.URL = url;
}
public void Dispose()
{
server.CloseAsync().Wait();
}
public void Start()
{
var config = new HttpSelfHostConfiguration(URL);
config.TransferMode = TransferMode.Streamed;
AddAPIRoute(config);
server = new HttpSelfHostServer(config);
var task = server.OpenAsync();
task.Wait();
//Console.WriteLine("Web API Server has started at:" + URL);
//Console.ReadLine();
}
private void AddAPIRoute(HttpSelfHostConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
From the main() [program.cs file] winform applition I call the webapi start function.
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
//Start the webAPI
WebApiProgram.StartMain();
Thread.CurrentThread.CurrentCulture
= Thread.CurrentThread.CurrentUICulture
= CultureInfo.InvariantCulture;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var mainForm = new MainForm();
Application.Run(mainForm);
}
}
I'm trying to host a Rest service i created in c#, deploying a .dll file and importing it in a new project with main method.
To create an host in the main I created an interface for my Rest service, but after the declaration of this interface i keep getting the error
"The name Content does not exist in the current context"
. Content is the return of my method, that should return only void or Task or Task T> because is async method.
How should I resolve this error?
This is part of the controller(Rest Service):
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.ServiceModel;
using Couchbase;
using Couchbase.Core;
using Couchbase.IO;
using JWT;
[ServiceContract]
public interface ApiController
{
Task<IHttpActionResult> SignUp(LoginModel model);
}
namespace Nerder_Backend.Controllers
{
[RoutePrefix("api/user")]
public class UserController : ApiController
{
private readonly IBucket _bucket = ClusterHelper.GetBucket(ConfigurationManager.AppSettings.Get("CouchbaseUserBucket"));
private readonly string _secretKey = ConfigurationManager.AppSettings["JWTTokenSecret"];
[Route("signup")]
[HttpPost]
public async Task<IHttpActionResult> SignUp(LoginModel model)
{
if (model == null || !model.IsValid())
{
return Content(HttpStatusCode.BadRequest, new Error("Invalid email and/or password"));
}
var userKey = CreateUserKey(model.Email);
if (await _bucket.ExistsAsync(userKey))
{
return Content(HttpStatusCode.Conflict, new Error($"email '{model.Email}' already exists"));
}
var userDoc = new Document<User>
{
Id = userKey,
Content = new User
{
Email = model.Email,
Password = CalcuateMd5Hash(model.Password)
},
Expiry = model.Expiry
};
var result = await _bucket.InsertAsync(userDoc);
if (!result.Success)
{
return Content(HttpStatusCode.InternalServerError, new Error(result.Message));
}
var data = new
{
token = BuildToken(model.Email)
};
var context = $"Created user with ID '{userKey}' in bucket '{_bucket.Name}' that expires in {userDoc.Expiry}ms";
return Content(HttpStatusCode.Accepted, new Result(data, context));
}
This is the main method :
namespace MockServer
{
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/signup");
// Create the ServiceHost.
using (ServiceHost host = new ServiceHost(typeof(UserController), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
}
}
}
Update main to host the web api properly.
include the following using statements
using System.Web.Http;
using System.Web.Http.SelfHost; //install the nuget package Microsoft.AspNet.WebApi.SelfHost
update Program class to Host the Web API
class Program {
static void Main(string[] args) {
var baseAddress = "http://localhost:8080";
var config = new HttpSelfHostConfiguration(baseAddress);
config.MapHttpAttributeRoutes();//map attribute routes
// Create the server
using (var server = new HttpSelfHostServer(config)) {
server.OpenAsync().Wait();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
}
}
}
Now make sure the api controller it correctly defined.
[RoutePrefix("api/user")]
public class UserController : ApiController {
private readonly IBucket _bucket = ClusterHelper.GetBucket(ConfigurationManager.AppSettings.Get("CouchbaseUserBucket"));
private readonly string _secretKey = ConfigurationManager.AppSettings["JWTTokenSecret"];
[HttpPost]
[Route("signup")] //Matches POST api/user/signup
public async Task<IHttpActionResult> SignUp(LoginModel model) {
//...code removed for brevity
}
}
Given the program set and controller attribute routes, the action would be found at
POST http://localhost:8080/api/user/signup
I am trying to self-host Web API. It works fine when I call requests through my program, where is API controller. But i can't make request through Postman Client. What could be the problem?
Api Controller
public class MyApiController : ApiController
{
public string Get()
{
return "Get";
}
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:44300/";
using (WebApp.Start<Startup>(url))
{
var client = new HttpClient();
var response = client.GetAsync(url + "api/myapi").Result;
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
Console.ReadLine();
}
}
It looks like your issues are in your main method. In C#, the using statement (link) creates a resource, executes the code in the block, and then disposes of the resource.
In your posted example, your WebApp is disposed right after it prints the response to the console (and before you're able to make requests with your browser).
These edits should allow you to keep the WebApp in-scope in order to play around with the framework.
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:44300/";
using (WebApp.Start<Startup>(url))
{
var client = new HttpClient();
var response = client.GetAsync(url + "api/myapi").Result;
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
Console.WriteLine("WebApp Ready");
Console.ReadLine();
}
Console.WriteLine("WebApp disposed.");
Console.ReadLine();
}
}
I need to make a simple webapi call to post method with string argument.
Below is the code I'm trying, but when the breakpoint is hit on the webapi method, the received value is null.
StringContent stringContent = new System.Net.Http.StringContent("{ \"firstName\": \"John\" }", System.Text.Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.PostAsync(url.ToString(), stringContent);
and server side code:
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
please help...
If you want to send a json to your Web API, the best option is to use a model binding feature, and use a Class, instead a string.
Create a model
public class MyModel
{
[JsonProperty("firstName")]
public string FirstName { get; set; }
}
If you wont use the JsonProperty attribute, you can write property in lower case camel, like this
public class MyModel
{
public string firstName { get; set; }
}
Then change you action, change de parameter type to MyModel
[HttpPost]
public void Post([FromBody]MyModel value)
{
//value.FirstName
}
You can create C# classes automatically using Visual Studio, look this answer here Deserialize JSON into Object C#
I made this following test code
Web API Controller and View Model
using System.Web.Http;
using Newtonsoft.Json;
namespace WebApplication3.Controllers
{
public class ValuesController : ApiController
{
[HttpPost]
public string Post([FromBody]MyModel value)
{
return value.FirstName.ToUpper();
}
}
public class MyModel
{
[JsonProperty("firstName")]
public string FirstName { get; set; }
}
}
Console client application
using System;
using System.Net.Http;
namespace Temp
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Enter to continue");
Console.ReadLine();
DoIt();
Console.ReadLine();
}
private static async void DoIt()
{
using (var stringContent = new StringContent("{ \"firstName\": \"John\" }", System.Text.Encoding.UTF8, "application/json"))
using (var client = new HttpClient())
{
try
{
var response = await client.PostAsync("http://localhost:52042/api/values", stringContent);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
}
}
}
}
}
Output
Enter to continue
"JOHN"
Alternative answer: You can leave your input parameter as string
[HttpPost]
public void Post([FromBody]string value)
{
}
, and call it with the C# httpClient as follows:
var kvpList = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("", "yo! r u dtf?")
};
FormUrlEncodedContent rqstBody = new FormUrlEncodedContent(kvpList);
string baseUrl = "http://localhost:60123"; //or "http://SERVERNAME/AppName"
string C_URL_API = baseUrl + "/api/values";
using (var httpClient = new HttpClient())
{
try
{
HttpResponseMessage resp = await httpClient.PostAsync(C_URL_API, rqstBody); //rqstBody is HttpContent
if (resp != null && resp.Content != null) {
var result = await resp.Content.ReadAsStringAsync();
//do whatevs with result
} else
//nothing returned.
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
Console.ResetColor();
}
}
For the record I tried the above and could not get it working!
I couldn't get it working because my API was in a separate project. Which is fine right? no, I was doing Dependency Injection into the controller while using the Startup class against the Base project.
You can resolve this by using the WebAPI's config and configuring Dependency Injection there with Unity. The below code works for me:
WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
RegisterUnity();
}
private static void RegisterUnity()
{
var container = new UnityContainer();
container.RegisterType<IIdentityRespository, IdentityRespository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
I hope it helps others :-)
I would like to return camel-cased JSON data using Web API. I inherited a mess of a project that uses whatever casing the previous programmer felt like using at the moment (seriously! all caps, lowercase, pascal-casing & camel-casing - take your pick!), so I can't use the trick of putting this in the WebApiConfig.cs file because it will break the existing API calls:
// Enforce camel-casing for the JSON objects being returned from API calls.
config.Formatters.OfType<JsonMediaTypeFormatter>().First().SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
So I'm using a custom class that uses the JSON.Net serializer. Here is the code:
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class JsonNetApiController : ApiController
{
public string SerializeToJson(object objectToSerialize)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
if (objectToSerialize != null)
{
return JsonConvert.SerializeObject(objectToSerialize, Formatting.None, settings);
}
return string.Empty;
}
}
The problem is that the raw data returned looks like this:
"[{\"average\":54,\"group\":\"P\",\"id\":1,\"name\":\"Accounting\"}]"
As you can see, the backslashes mess things up. Here is how I'm calling using the custom class:
public class Test
{
public double Average { get; set; }
public string Group { get; set; }
public int Id { get; set; }
public string Name { get; set; }
}
public class SomeController : JsonNetApiController
{
public HttpResponseMessage Get()
var responseMessage = new List<Test>
{
new Test
{
Id = 1,
Name = "Accounting",
Average = 54,
Group = "P",
}
};
return Request.CreateResponse(HttpStatusCode.OK, SerializeToJson(responseMessage), JsonMediaTypeFormatter.DefaultMediaType);
}
What can I do differently to get rid of the backslashes? Is there an alternative way to enforcing camel-casing?
Thanks to all the references to other Stackoverflow pages, I'm going to post three solutions so anyone else having a similar issue can take their pick of the code. The first code example is one that I created after looking at what other people were doing. The last two are from other Stackoverflow users. I hope this helps someone else!
// Solution #1 - This is my solution. It updates the JsonMediaTypeFormatter whenever a response is sent to the API call.
// If you ever need to keep the controller methods untouched, this could be a solution for you.
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http;
using Newtonsoft.Json.Serialization;
public class CamelCasedApiController : ApiController
{
public HttpResponseMessage CreateResponse(object responseMessageContent)
{
try
{
var httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, responseMessageContent, JsonMediaTypeFormatter.DefaultMediaType);
var objectContent = httpResponseMessage.Content as ObjectContent;
if (objectContent != null)
{
var jsonMediaTypeFormatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
};
httpResponseMessage.Content = new ObjectContent(objectContent.ObjectType, objectContent.Value, jsonMediaTypeFormatter);
}
return httpResponseMessage;
}
catch (Exception exception)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, exception.Message);
}
}
}
The second solution uses an attribute to decorate the API controller method.
// http://stackoverflow.com/questions/14528779/use-camel-case-serialization-only-for-specific-actions
// This code allows the controller method to be decorated to use camel-casing. If you can modify the controller methods, use this approach.
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http.Filters;
using Newtonsoft.Json.Serialization;
public class CamelCasedApiMethodAttribute : ActionFilterAttribute
{
private static JsonMediaTypeFormatter _camelCasingFormatter = new JsonMediaTypeFormatter();
static CamelCasedApiMethodAttribute()
{
_camelCasingFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
public override void OnActionExecuted(HttpActionExecutedContext httpActionExecutedContext)
{
var objectContent = httpActionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
if (objectContent.Formatter is JsonMediaTypeFormatter)
{
httpActionExecutedContext.Response.Content = new ObjectContent(objectContent.ObjectType, objectContent.Value, _camelCasingFormatter);
}
}
}
}
// Here is an example of how to use it.
[CamelCasedApiMethod]
public HttpResponseMessage Get()
{
...
}
The last solution uses an attribute to decorate the entire API controller.
// http://stackoverflow.com/questions/19956838/force-camalcase-on-asp-net-webapi-per-controller
// This code allows the entire controller to be decorated to use camel-casing. If you can modify the entire controller, use this approach.
using System;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http.Controllers;
using Newtonsoft.Json.Serialization;
public class CamelCasedApiControllerAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings httpControllerSettings, HttpControllerDescriptor httpControllerDescriptor)
{
var jsonMediaTypeFormatter = httpControllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
httpControllerSettings.Formatters.Remove(jsonMediaTypeFormatter);
jsonMediaTypeFormatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
};
httpControllerSettings.Formatters.Add(jsonMediaTypeFormatter);
}
}
// Here is an example of how to use it.
[CamelCasedApiController]
public class SomeController : ApiController
{
...
}
If you want to set it globally you can just remove the current Json formatter from the HttpConfiguration and replace it with your own.
public static void Register(HttpConfiguration config)
{
config.Formatters.Remove(config.Formatters.JsonFormatter);
var serializer = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var formatter = new JsonMediaTypeFormatter { Indent = true, SerializerSettings = serializer };
config.Formatters.Add(formatter);
}
Comment on https://stackoverflow.com/a/26506573/887092 works for some cases but not others
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
This way works in other cases
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
So, cover all bases with:
private void ConfigureWebApi(HttpConfiguration config)
{
//..
foreach (var jsonFormatter in config.Formatters.OfType<JsonMediaTypeFormatter>())
{
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
var singlejsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
singlejsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}