Windows service accessing LocalDb returns empty - c#

I have a C# dll to query data using Entity Framework. After that I use owin to create a rest api to reference the dll to get data. I have two samples: one is use a console app to access the data, and it's ok. The other is I put the rest api inside a Windows service, and access it. It returns empty. I don't know why.
C# dll:

ef dll:
public class DemoContext:DbContext
{
private static DemoContext _instance;
public DemoContext() : base("MyDemoConnection")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DemoContext, Configuration>());
}
public static DemoContext Instance
{
get
{
if (_instance == null)
{
_instance = new DemoContext();
}
return _instance;
}
}
public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; }
}
owin api:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
public class TeachersController : ApiController
{
[HttpGet]
[Route("api/teachers")]
public HttpResponseMessage Get()
{
try
{
var _context = DemoContext.Instance;
var teachers = _context.Teachers.ToList();
var response = Request.CreateResponse(HttpStatusCode.OK, teachers);
return response;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.OK, ex.Message);
}
}
}
console app:
class Program
{
static void Main(string[] args)
{
string baseAddress = "http://localhost:9000/";
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
// Create HttpCient and make a request to api/values
/* HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync(baseAddress + "api/values").Result;
var result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);*/
Console.ReadLine();
}
}
}
windowservice:
public partial class HostOwin : ServiceBase
{
private IDisposable owin;
public HostOwin()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
string baseAddress = "http://localhost:9000/";
owin = WebApp.Start<Startup>(url: baseAddress);
}
protected override void OnStop()
{
owin.Dispose();
}
}

Related

Web API Self Hosted on windows service using OWIN , Complex Objects always null

I have Web API Project , it is referencing dll of database entities , it contain API Controllers , that return complex objects
when i test the Web API using visual studio (browser) or Telerik Fiddler before hosting the API on windows service , it is working fine and return a json of complex objects as expected .
After i create another project for windows service to self host the wep API using Owin
when i test any controller that return a complex object , it always return null while if i test any controller that return simple string , it is working fine , please help
I don't know why same things don't work after host on windows service
here my windows service startup.cs file
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
var assembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
string path = assembly.Substring(0, assembly.LastIndexOf("\\")) + "\\API.dll";
config.Services.Replace(typeof(IAssembliesResolver), new SelfHostAssemblyResolver(path));
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
here is windows service class which inherit from service base class
public partial class selfHosting : ServiceBase
{
public string baseAddress = "http://localhost:9000/";
private IDisposable _server = null;
public selfHosting()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_server = WebApp.Start<Startup>(url: baseAddress);
}
protected override void OnStop()
{
if (_server != null)
{
_server.Dispose();
}
base.OnStop();
}
}
below is WebApiConfig File under another project (API)
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
}
}
after i check localhost:9000/api/employee
it return this line
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ArrayOfEmployees xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Application.Model" i:nil="true"/>
Controller in web API Project
public class employeeController : ApiController
{
static readonly IRepository<employee> repository = new employeeRepository();
// GET api/<controller>
public IEnumerable<employee> Get()
{
return repository.GetAll();
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
// POST api/<controller>
public void Post([FromBody]string value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
if the get() method return simple string , it is working fine
for example
// GET api/<controller>
public string Get()
{
return "Hello" ;
}

ASP.NET Self hosted Web API with IE – This page cannot be displayed

I am trying to invoke my service locally but IE and Edge are not able to find it.
Below is the code snippet I have and my console app is working without any error.
Program.cs
public class Program
{
static void Main()
{
string baseAddress = "http://127.0.0.1:8080/";
// Start OWIN host
using (WebApp.Start(url: baseAddress))
{
Console.WriteLine("Service Listening at " + baseAddress);
System.Threading.Thread.Sleep(-1);
}
}
}
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
WebController.cs
public class Web
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class WebController : ApiController
{
Web[] websites = new Web[]
{
new Web { Id = 1, Name = "XYZ", Description = "XYZ"},
new Web { Id = 2, Name = "ABC", Description = "ABC"}
};
// GET api/Web
public IEnumerable Get()
{
return websites;
}
// GET api/Web/5
public Web Get(int id)
{
try
{
return websites[id];
}
catch (Exception e)
{
return new Web();
}
}
// POST api/values
public void Post([FromBody]string value)
{
Console.WriteLine("Post method called with value = " + value);
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
Console.WriteLine("Put method called with value = " + value);
}
// DELETE api/values/5
public void Delete(int id)
{
Console.WriteLine("Delete method called with id = " + id);
}
}
I am invoking my service on IE like everyone does: http://127.0.0.1:8080/api/web to GET entire Web Object.
I have installed two additional packages, OWIN and CORS.
Could someone help find a solution for this issue.
I have just tried and your api works correctly in Edge and Chrome. It can be that IE don't send correct Accept header which causes to either server to return wrong result or error or IE cannot interpret the response. Actually, I have check and IE offers to save json file because it cannot display it correctly.
To show it explicitly I have modified you code a bit:
public IHttpActionResult Get(string type = null)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
if (type == "json")
{
response.Content = new StringContent(JsonConvert.SerializeObject(websites));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
else if (type == "xml")
{
response.Content = new StringContent("<xmlTag>Value</xmlTag>");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
}
return ResponseMessage(response);
}
Try follow http://127.0.0.1:8080/api/web?type=json and http://127.0.0.1:8080/api/web?type=xml urls and check yourself.

Routes not mapping correctly when creating in memory web api server

When I curl to the /test route it works fine, however the test below 404's when trying to hit the in memory server on the same route.
When inspecting _client and _config appear to be ok - although I am not sure how to confirm that my in memory server is functioning correctly.
Does anybody know how I can get my in memory web server to map it's routes correctly so my test method can reach it?
namespace Robo.Tests.Controllers
{
[TestClass]
public class IntegrationTests
{
private HttpMessageInvoker _client;
private HttpConfiguration _config = new HttpConfiguration();
[TestInitialize]
public void SetupTest()
{
_config.MapHttpAttributeRoutes();
_config.EnsureInitialized();
var server = new HttpServer(_config);
_client = new HttpMessageInvoker(server);
}
[TestMethod]
public async Task Test()
{
var result = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://localhost/test"), CancellationToken.None);
}
}
}
and controller in case you are interested
namespace Robo.Controllers
{
//[ValidationActionFilter]
public class CVController : ApiController
{
[HttpGet]
[Route("test")]
public async Task<IHttpActionResult> test()
{
return Ok();
}
}
}
For in-memory server testing The following utility class was created. It basically wraps the setup functionality in the example shown.
internal interface IHttpTestServer : IDisposable {
HttpConfiguration Configuration { get; }
HttpClient CreateClient();
}
internal class HttpTestServer : IHttpTestServer {
HttpServer httpServer;
public HttpTestServer(HttpConfiguration configuration = null) {
httpServer = new HttpServer(configuration ?? new HttpConfiguration());
}
public HttpConfiguration Configuration {
get { return httpServer.Configuration; }
}
public HttpClient CreateClient() {
var client = new HttpClient(httpServer);
return client;
}
public void Dispose() {
if (httpServer != null) {
httpServer.Dispose();
httpServer = null;
}
}
public static IHttpTestServer Create(HttpConfiguration configuration = null) {
return new HttpTestServer(configuration);
}
}
The following test was crafted to demonstrate the use of in memory server using OP
[TestClass]
public class IntegrationTests {
[TestMethod]
public async Task Test() {
using (var server = HttpTestServer.Create()) {
//Arrange
var config = server.Configuration;
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
var client = server.CreateClient();
var url = "http://localhost/test";
var request = new HttpRequestMessage(HttpMethod.Get, url);
var expected = System.Net.HttpStatusCode.OK;
//Act
var result = await client.SendAsync(request, CancellationToken.None);
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(expected, result.StatusCode);
}
}
public class CVController : ApiController {
[HttpGet]
[Route("test")]
public async Task<IHttpActionResult> test() {
return Ok();
}
}
}
Test passes.
The thing about this example is that the test and controller exist in same assembly so map attribute scans the assembly it was called in and found API controller with attribute routes. If controller lived in another project then the web API config of that project should be called on the HttpConfiguration to properly configure web API.
UPDATE
The test project and web api project should be two separate projects. That said, The web project should have a WebApiConfig.cs file with a static WebApiConfig.Register class and method. That method takes a HttpConfiguration parameter. The test should use that method to configure the api for in memory calls.
[TestClass]
public class IntegrationTests {
[TestMethod]
public async Task Test() {
using (var server = HttpTestServer.Create()) {
//Arrange
var config = server.Configuration;
//Config server
MyWebApiNamespace.WebApiConfig.Register(config);
var client = server.CreateClient();
var url = "http://localhost/test";
var request = new HttpRequestMessage(HttpMethod.Get, url);
var expected = System.Net.HttpStatusCode.OK;
//Act
var result = await client.SendAsync(request, CancellationToken.None);
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(expected, result.StatusCode);
}
}
}

How to get a list on Windows Phone 8.1 using WebApi

How can I do a GET using Windows Phone based on my Web API code? To make a Post i already know and Works for me, but i don't know to retrieve a list of Collections from my API, Thanks!
My API Code:
public class UsersController : ApiController
{
private ApiDatabaseEntities data = new ApiDatabaseEntities();
public IHttpActionResult GetUsuarios()
{
try
{
IEnumerable<Usuario> usuarios = data.Usuario.AsEnumerable();
return Ok(usuarios.AsEnumerable());
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
public IHttpActionResult PostUsuarios(Usuario usuario)
{
try
{
data.Usuario.Add(usuario);
data.SaveChanges();
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
And here is my Windows phone code:
1 - WebApiBase
public abstract class WebApiBase<T>
{
private string Url = "http://localhost:63964/api/users";
protected virtual void Post(object objectPost)
{
HttpClient client = new HttpClient();
client.PostAsJsonAsync(Url, objectPost);
}
public abstract void Send(T objectPost);
}
2 - And UsuarioApi
public class UsuarioApi : WebApiBase<Models.UserPhone>
{
public override void Send(UserPhone objectPost)
{
this.Post(objectPost);
}
}
For Sending get request to server from Windows Phone and then handling the response from server.
public async void GetRequest(){ string url = "APIurl";
HttpClient _client = new HttpClient();
HttpResponseMessage _response = await _client.GetAsync(new Uri(url));
if (_response.IsSuccessStatusCode)
{
string APIResponse = await _response.Content.ReadAsStringAsync();
var myObject = Newtonsoft.Json.Linq.JArray.Parse(APIResponse).ToObject<MyClass>();
}
}
and MyClass
public class MyClass
{
public ObservableCollection<CollectionClass> _myCollection{get;set;}
}
public class CollectionClass
{
public string Name{get;set;}
}
and now You can perform operations on myObject as per your requirement.

AuthorizeAttribute being bypassed in Web API when using media formatters

I've created a web api application, to expose an ODATA API, to a front-end application. One of the reasons for doing this was to be able to return different content types, such as Excel files, for the same data.
I've made use of a custom Media Formatter to output my Excel data, however, I've noticed that when I call it, from the client, there is no security in place.
When making a GET, with no ACCEPT header, then the OAuth bearer token is checked and access is either accepted or revoked. The Authorization is set via [Authorize] on the controller.
When I make the same GET, with the ACCEPT header set to request an Excel file, the controller is called regardless of the token, bypassing the security on the controller.
I've obviously done something wrong, however, I can't work out what it could be. It's the same controller but for some reason, it's always allowing access when ACCEPT is set to a supported media type.
A cut-down version of my set up is below.
Owin Startup:
[assembly: OwinStartup(typeof(Rest.Startup))]
namespace Rest
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
private void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions oauthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorisationServerProvider()
};
// Token generation
app.UseOAuthAuthorizationServer(oauthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
}
The call into WebApiConfig.Register()
namespace Rest
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.Add(new ExcelSimpleFormatter());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Configure CORS globally
var cors = new EnableCorsAttribute(
origins:"*",
headers:"*",
methods:"*");
config.EnableCors(cors);
}
}
}
My media formatter (code removed to save space):
namespace Rest.Formatters
{
public class ExcelSimpleFormatter : BufferedMediaTypeFormatter
{
public ExcelSimpleFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/excel"));
}
public override bool CanWriteType(Type type)
{
return true;
}
public override bool CanReadType(Type type)
{
return false;
}
public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
// This gets called regardless of authorization
}
}
}
An example / simplified controller:
namespace Rest.Controllers
{
[Authorize]
public class TestController : ApiController
{
private dbSDSContext db = new dbSDSContext();
// GET: api/Test
public IQueryable<test> GetTests()
{
return db.test;
}
// GET: api/Test/5
[ResponseType(typeof(test))]
public async Task<IHttpActionResult> GetTest(int id)
{
test test = await db.test.FindAsync(id);
if (test == null)
{
return NotFound();
}
return Ok(test);
}
// PUT: api/Test/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutTest(int id, test test)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != test.testID)
{
return BadRequest();
}
db.Entry(test).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TestExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Test
[ResponseType(typeof(test))]
public async Task<IHttpActionResult> PostTest(test test)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.test.Add(test);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new { id = test.testID}, test);
}
// DELETE: api/Test/5
[ResponseType(typeof(test))]
public async Task<IHttpActionResult> DeleteTest(int id)
{
test test = await db.test.FindAsync(id);
if (test == null)
{
return NotFound();
}
db.test.Remove(test);
await db.SaveChangesAsync();
return Ok(test);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool TestExists(int id)
{
return db.test.Count(e => e.testID == id) > 0;
}
}
}
The error was caused by using the wrong namespace in the controllers affected.
When using WebAPI ensure to use:
using System.Web.Http;
and not:
using System.Web.Mvc;

Categories