How to make Owin self host support Json output? - asp.net

I am using Owin to build a self hosted server which support both file requests and web api. But the output for web api requests are always in xml format. How can I configure owin to output in json?
The code is as below:
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseFileServer(new FileServerOptions()
{
RequestPath = PathString.Empty,
FileSystem = new PhysicalFileSystem(#".\files")
});
// set the default page
app.UseWelcomePage(#"/index.html");
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute
(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
app.UseWebApi(config);
}
}

I have found the answer myself. All have to do is to add a json formatter as below:
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.JsonFormatter.SerializerSettings =
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
If need to convert enum to string add StringEnumConverter to the settings.
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringEnumConverter());

Related

This method or property is not supported after HttpRequest.GetBufferlessInputStream has been invoked request.Files

I am using ASP.NET FW 4.6.1; Microsft.AspNet.WebApi 5.2.7; EF 6.4.
I have the issue below when starting my project.
Method request.Files is not supported (please see image)
public static class WebApiConfig
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "<Pending>")]
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Enable cross domain request
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Filters.Add(new ErrorHandlers.AiHandleErrorAttribute());
**config.Filters.Add(new UploadFileFilterAttribute());**
config.MessageHandlers.Add(new RequestTabletMessageHandler());
config.MessageHandlers.Add(new RequestLoggingMessageHandler());
config.Services.Add(typeof(IExceptionLogger), new CustomExceptionLogger());
}
}
The reason it is not supported is because the file buffer stream has already been parsed (or parsing has started) at a previous point in the request pipeline. You should look at other filters/modules in your pipeline and see if any of them touch the files in the incoming request. You might find that simply commenting out other filters (such as ErrorHandlers.AiHandleErrorAttribute() for example) and rerunning could be used to quickly determine which filter/module is doing the parsing. Once you have figured that out, you need to decide how you are going to handle multiple parses of the files. One option is to only use one module, another would be to buffer it into a memory stream/block of memory and have both/all modules access that copy instead. Hope this helps.

How to convert a datatable to json ASP.NET

I am trying to get data from database using ASP.NET CORE API the problem that I can't convert the datatable to JSON
I used this solution but i got the same problem.
This is what I get every time I test with Postman
"[{\"id_auxiliaire\":\"0000000008522450131\",\"identite_fiscal_cin\":\"0XDERTTOL45\",\"NOM_RAISON_SOCIALE\":\"HIGHTech\",\"CodePostale\":41225,\"Ville\":\"USA\"},}]"
This is my WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Configure Web API to return JSON
config.Formatters.JsonFormatter
.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));
}
}
And this is my code
SqlDataAdapter da = new SqlDataAdapter($"select * from [UserDetail] WHERE CONVERT(date, dateOperation) BETWEEN '{dd}' AND '{df}' ", con);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0)
{
string res = JsonConvert.SerializeObject(dt, Formatting.None);
return new string[] { res };
}

Access-Control-Allow-Origin error when using Owin

I'm have a aurelia client and a webserver. When i use localhost and i'm running on the same machine it works fine.
But when i want to access the server from another machine the page loads but the api calls give the following error:
No Access-Control-Allow-Origin header is present on the requested resource.
I'm using owin and to my undestanding i need to enable CORS for owin.
I did the follwing in my startup class:-
UPDATE
I have updated my class with input from Nenad but is still get the same error.
Below i have added the call from the client.
public void Configuration(IAppBuilder app)
{
this.container = new Container();
// Create the container as usual.
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
// Register your types, for instance using the scoped lifestyle:
container.Register<IWebDeps, WebDeps>(Lifestyle.Singleton);
// This is an extension method from the integration package.
container.RegisterWebApiControllers(GlobalConfiguration.Configuration, Assembly.GetExecutingAssembly());
container.Verify();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// Configure Web API for self-host.
var config = new HttpConfiguration()
{
DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container)
};
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//// Custom Middleare
app.Use(typeof(CustomMiddleware));
app.UseWebApi(config);
//New code:
app.Run(context =>
{
context.Response.ContentType = "text/plain";
return context.Response.WriteAsync("Hello, world.");
});
}
My main program is calling the startUp class:-
using (Microsoft.Owin.Hosting.WebApp.Start<Startup>("http://localhost:8080"))
{
Console.WriteLine("Press [enter] to quit...");
Console.ReadLine();
}
Client code, 192.168.178.23 is the ip from the server.
let baseUrl2 = "http://192.168.178.23:8080/api/status/getStatus";
getStatus() {
return this.client.get(baseUrl2)
.then(response => {
return this.parseJSONToObject(response.content);
});
}
The error in Chrome:
XMLHttpRequest cannot load
http://192.168.178.23:8080/api/status/getStatus. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:9000' is therefore not allowed
access. The response had HTTP status code 400.
Cors should be enabled now right? But i still get the error when doing a api call. Am i missing any steps? Our is this approah wrong?
Any suggestions are welcome!
You have to configure WebAPI to work with CORS.
Install Nuget package:
Install-Package Microsoft.AspNet.WebApi.Cors
Enable CORS on HttpConfiguration object:
config.EnableCors();
Add [EnableCors] attribute on your controller:
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
namespace WebService.Controllers
{
[EnableCors(origins: "www.example.com", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
}
or register it globally via HttpConfig:
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
More details at: Enabling Cross-Origin Requests in ASP.NET Web API 2
Add this line and check,
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
and remove,
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
this worked for me.
Turns out that when starting OWIN the adres should be http://*:8080. Instead of local host.

How to call a web api from url in mvc4

I have created a web api with two parameters. I want to test it from url that its working or not. I have tried but not able to call. My code is.
API routing...
public static void Register(HttpConfiguration config)
{
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
[HttpGet]
public List<Library> GetLibrary(string DataType, int DataId)
{
List<Library> LibraryList = new List<Library>();
if (DataType == "Course")
{
using (ICA.LMS.Service.Models.Entities dbCourse = new Models.Entities())
{
LibraryList = (from c in dbCourse.COURSELIBRARies
where c.LIBITEMID == DataId
select new Library { Id = c.LIBITEMID, Name = c.GROUPNAME, Desc = c.DESCRIPTION }).ToList();
}
}
return LibraryList;
}
Url which i am putting in browser.
http://localhost:1900/api/librarybyid/?DataType='Course'&DataId=1
Result i am getting...
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:1900/api/librarybyid/?DataType='Course'&DataId=1'.
</Message>
<MessageDetail>
No type was found that matches the controller named 'librarybyid'.
</MessageDetail>
</Error>

Authorize Filter in Web Api 2.0 With OauthBearerTokens Not Working

I have a Single Page Application (Angular Js + AspNet Web API) using OAuthBearerToken style authentication
My Code Is as follows
[assembly: OwinStartupAttribute(typeof(App.Web.Startup))]
namespace App.Web
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.SuppressDefaultHostAuthentication();
config.Formatters.Remove(config.Formatters.XmlFormatter);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Filters.Add(new ValidateModelStateAttribute());
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//register autofac
var builder = new ContainerBuilder();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterFilterProvider();
builder.RegisterModelBinderProvider();
builder.RegisterWebApiFilterProvider(config);
builder.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
ConfigureOAuth(app, container);
}
public void ConfigureOAuth(IAppBuilder app, IContainer container)
{
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = container.Resolve(typeof(SimpleAuthorizationServerProvider)) as IOAuthAuthorizationServerProvider
};
app.UseOAuthBearerTokens(oAuthServerOptions);
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
}
My SimpleAuthorizationProvider Implementation is as listed below
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});
var userManager = context.OwinContext.GetAutofacLifetimeScope().Resolve<IUserStore<User>>() as UserStore;
if (userManager != null)
{
var user = await userManager.FindByNameAsync(context.UserName);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
var phash = await userManager.GetPasswordHashAsync(user);
//the hash of the incoming password
var passwordHasher = new PasswordHasher();
var result = passwordHasher.VerifyHashedPassword(phash, context.Password);
if (result == PasswordVerificationResult.Success)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Sid, user.Id.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Email, user.UserName));
context.Validated(identity);
}
else
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
}
}
}
}
Now here goes the problem
When I Issue a post request to the /token endpoint. Everything works well and I get a bearer token returned
Whenever i try to access an action method annotated with the authorize attribute with HTTP Authorization Header set to Bearer {access_token} I get the message
"Authorization has been denied for this request".
Please Am I doing something wrong?
You should sent the token in the Authorization header using Bearer scheme.
I guess you are sending it as part of the query string, that is why your API protected endpoints are not understanding it. Please check my detailed post about AngularJS authentication with Web API which covers your exact scenario.
Do you have a WebApiConfig.cs file in your project, with Register(HttpConfiguration config) method in it ?
If you do, then it should contain the following :
public static void Register(HttpConfiguration config)
{
// Move config.SuppressDefaultHostAuthentication() from Startup::Register method to this method
config.SuppressDefaultHostAuthentication();
// Add a filter handling "Bearer" authentication to the known filters
config.Filters.Add(new HostAuthenticationFilter("Bearer"));
}
I was having the same problem as you, and fixed it with this.
The solution was brought by https://stackoverflow.com/a/34166821/867600.
how do you pass the header in your request ? it should be
Authorization: Bearer imSXTs2OqSrGWzsFQhIXziFCO3rF...
// If we already have a bearer token, set the Authorization header.
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
$.ajax({
type: 'GET',
url: 'api/values/1',
headers: headers
}).done(function (data) {
self.result(data);
}).fail(showError);
see this link, it has a very good details.
Hope that helps.

Resources