MVC 6 - Web API 2.0 white space on parameter URL - c#

I'm trying to do a search on my Web API URL, as follows:
http://localhost:8000/api/trips/World Trip/stops
In this case, "World Trip" is the word. But when the call arrives on the server, it arrives as follows:
"World%20Trip" with code %20 to replace the empty space!
IS there some setting that has to be made to prevent substituting the space with code? I remember <httpRuntime relaxedUrlToFileSystemMapping="true" /> in previous versions.
I do not want to use any method for conversion within the server: Such as HttpServerUtility.UrlEncode().
My Data Annotation route:
[Route("api/trips/{tripName}/stops")]
My StopController.cs
using AutoMapper;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using TheWorld.Models;
using TheWorld.ViewModels;
namespace TheWorld.Controllers.Api
{
[Route("api/trips/{tripName}/stops")]
public class StopController : Controller
{
private ILogger<StopController> _logger;
private IWorldRepository _repository;
public StopController(IWorldRepository repository, ILogger<StopController> logger)
{
_repository = repository;
_logger = logger;
}
[HttpGet("")]
public JsonResult Get(string tripName)
{
try
{
var results = _repository.GetTripByName(tripName);
if (results == null)
{
return Json(null);
}
return Json(Mapper.Map<IEnumerable<StopViewModel>>(results.Stops.OrderBy(s => s.Order)));
}
catch (Exception ex)
{
_logger.LogError($"Failed to get stops for trip {tripName}", ex);
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error occurred finding trip name");
}
}
}
}

You can just use HttpUtility.UrlDecode(yourstring) and you will have a more secure application.

I have had the same problem when walking through the pluralsight tutorial "Building a Web App with ASP.net 5, MVC 6, EF7 and AngularJS".
I solved the issue by using the code below,
tripName = WebUtility.UrlDecode(tripName);
This appears to be a bug in beta-8. Upgrade to rc1 and your problem should be solved.

I agree with user1919597 an upgrade all your packages and install the newest ASP version to rc1-update1 (this is the newest as of 11/30 up to this post date). See Shawn's Blog Post to perform all the updates you will need
Afterwards, you can test that the code is picking up the tripName in the URL bypassing it into the error message as follows
return Json($"Error occurred finding trip name {tripName}");
If the code returns an error it will pass in the tripName string from the url - for example: http://localhost:5151/api/trips/World%20Trip/stops will return "Error occurred finding trip name World Trip".
Now if your only getting an error message, instead of data, then something else may be going on...which happens to be the issue I am currently facing with this part of the course...its been 2 days of searching with no true fix...
All and All - Start with updating everything according to Shawn's Blog and then test this out again. Good Luck and I am interested to know how it turns out.

Related

Devart Error when I return database object with IActionResult

I am trying to return the database object that I get from my service in an IActionResult API Call (c# web API project). Whenever I attempt to do that I get this error:
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.
Here is my API code that is throwing this:
[HttpGet]
[Route("content")]
public IActionResult GetAllContent()
{
try
{
List<Content> allContent = _contentService.GetAll();
return Ok(allContent);
}
catch (Exception ex)
{
//Log something here
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
I could easily mitigate the error by parsing through the content and creating a dynamic object, but I find it annoying to do whenever I want to return a database object when I'm using the Devart Database Context.
Edit:
Further piece of the error message is this:
$.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.PortalCodeMappings.Content.ContentId.
And I understand the circular reference here, is there a way to tell devart I only want the Content section of this without doing something like this:
allContent.Select(x => new { ... });
Edit: I am using Devart Entity Devloper to generate my models and the dbcontext. I do not use Visual Studio or any IDE.
There are two alternative ways to solve the issue:
Use System.Text.Json (de)serialization
Add JsonIgnoreAttribute to one of the navigation property ends
You can add a custom attribute via the interface of Entity Developer this way:
a) navigate to Model > Settings > Attributes > select the System.Text.Json.dll assembly and make sure that JsonIgnoreAttribute is checked in the window below, press OK
b) select JsonIgnoreAttribute in the Attributes collection of a particular class property

Execution of SetCommandTimeout not working with EF Core 5 for PostgreSQL

I have a problem when I SetCommandTimeout is like the method is not working properly.
I Use PostgreSQL as database, and for the EntityFramework Core I'm using Npgsql.EntityFrameworkCore.PostgreSQL with Version 5.0.5.1
In the code I Set Timeout for 1s like this context.Database.SetCommandTimeout(1); and I set a Stopwatch to check how much time it takes, but the ElapsedMiliseconds always return around 15000ms to 16000ms. so the SetCommandTimeout(1) is clearly not working.
I also tried using context.Database.SetCommandTimeout(TimeSpan.FromSeconds(1)); is not working either.
One more thing, I only want to Set Timeout for specific Request. So the other Request will have the default timeout.
Here's my code:
[Route("api/[controller]")]
[ApiController]
public class TestController : Controller
{
private readonly DatabaseContext context;
public TestController(DatabaseContext context)
{
this.context = context;
}
[AllowAnonymous]
[HttpGet]
public async Task<IActionResult> Test()
{
var sw = Stopwatch.StartNew();
try
{
context.Database.SetCommandTimeout(1);
var test = await context.Test.FirstOrDefaultAsync();
return Ok();
}
catch (Exception)
{
return BadRequest();
}
finally
{
sw.Stop();
var elapsed = sw.ElapsedMilliseconds; // always return around 15000ms to 16000ms
}
}
}
here's how I register it in Startup.Cs
services.AddDbContext<DatabaseContext>(options =>
{
options.UseNpgsql(ConnectionString);
});
did I missing something?
Thanks in advance
The command timeout is the time a query / command is allowed to execute on the database server. The timer starts when the database server receives the request. Your end-to-end round trip time may be higher than the command timeout due to network throughput or other constraints - including resource exhaustion on your web server.
Command Timeout: The time to wait (in seconds) while trying to execute a command before terminating the attempt and generating an error.
Source
Googled a little and found issues related to this library.
Based on this forum post, it seems that the issue is coming from the source code and the settings is just being ignored.
Try to set-up command timeout inside the creating of DB context instead right before usage.
Another one is at the github repository.
Solution for this one is to upgrade to latest version of drivers.
Another from github.
The workaround for this is to modify connection string during creation of context:
if (!connectionString.Contains("CommandTimeout"))
{
connectionString += $";CommandTimeout=120";
}
EDIT (after OP mentioned he wants to use it on single request): I would recommend by going the way with creating other database context and modifying its connection string (as above). That way you would be able to execute short/long running commands. However, this brings other issues related to the multiple DB-context and possible mismatch of data. Needs to be handled with caution.

Global Error Handling in ASP.NET Web API 2

Preamble: This question is different from "Exception Handling in ASP.net Web API" as the OP was looking for custom Error Handling, not global handling. It also differs from other earlier questions that were answered, as those were for earlier versions of Web API, not version 2. Also note I am going to self answer this question. It took quite some searching to find the correct answer.
The question is: How do I globally handle errors in Web API 2.0? The error handling I have set up for MVC does not get activated for web api calls and I need to generically handle any error that is thrown so that relevant error information is returned to the client.
Global Error handling is correctly answered in this asp.net article. However the articles is missing a few important points to make the code actually work.
The article covers the details, but here it is in a nutshell:
Global Error Handling is already included in System.Web.Http.ExceptionHandling The classes in the article are already in this library, so there is no need to rewrite them.
The only class you need to write is the one which is customized for your app. In the article, they call it the "OopsExceptionHandler" However, the one written in the article does not compile. This is the updated code that does work:
public class OopsExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult
{
//If you want to return the actual error message
//Content = context.Exception.Message
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong." +
"Please contact support#contoso.com so we can try to fix it."
};
}
private class TextPlainErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response =
new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
You then need to register the ExceptionHandler. An example of this is not given in the article, so here it is:
config.Services.Replace(typeof(IExceptionHandler), new OopsExceptionHandler());
This line goes in the WebApiConfig file, in the register method. Note that it is using 'Replace' not 'Add' as it will error out on Add. Only one is allowed by the framework.
That is all that is required. To test, throw an error from your web API and you will see the error message returned as the content of the webAPI call. Note that there are security implications to returning error messages to the client, so make sure this is what you really want.

How to track 500 errors on WebSockets (ws://)

I'm trying to play around with WebSockets on IIS 8.5. I started off with a couple of very basic C# classes from a lesson:
using Microsoft.Web.WebSockets;
using System.Web;
public class ChatHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
context.AcceptWebSocketRequest(new WebSocketChatHandler());
}
public bool IsReusable
{
get { return true; }
}
}
public class WebSocketChatHandler : WebSocketHandler
{
private static WebSocketCollection clients = new WebSocketCollection();
private string name;
public override void OnOpen()
{
this.name = this.WebSocketContext.QueryString["username"];
clients.Add(this);
clients.Broadcast(string.Format("{0} joined.", name));
}
public override void OnMessage(string message)
{
clients.Broadcast(string.Format("{0}: {1}", name, message));
}
public override void OnClose()
{
clients.Remove(this);
clients.Broadcast(string.Format("{0} left.", name));
}
}
and a simple HTML client. The project builds ok, but when I try to connect to the handler, it returns error 500. The problem is that I cannot see what the exact error is, because neither Chrome nor FF load the response body for ws:// scheme, so i cannot even see it in the Network tab of Developer Tools (though IIS provides the body, as I can see from from the response' Content-Length).
Is there a way to see the response body in this situation? Or what am I missing with WebSockets in IIS?
The problem was with web.config.
I added
<httpRuntime targetFramework="4.5.1" />
to system.web section and it finally began to work
You should be able to see the cause of the error in the Windows Event Viewer.
Fiddler will show you the connection and that it has upgraded to web socket so you can use that tool to at least show you if the connection worked or not. I'm not aware of a tool which can show you the traffic flowing over the socket once it has been upgraded although there might be one.
Better still, debug it in Visual Studio with breakpoints and 'break on exception' set. You can tell VS to use IIS as the server by right clicking the web site and going to Property Pages then Start Options. Tick Use custom server and put your URL into the textbox. Click Specific page and choose your default page.
Comparing it to my working solution using the same DLL, I don't spot any obvious issues with the handling of the socket, so I would suggest commenting out this.name = this.WebSocketContext.QueryString["username"]; for now and replacing it with this.name = "TEST"; as that appears to be about the only code which deviates from the samples. Keep it simple until its working!

SignalR ASPNetHost does not exist in the current context

I've downloaded the latest SignalR code (as of 04/04/12) from GitHub as it now compiles with MonoDevelop so I can use it on OS X.
But while testing the new version with the SignalR.Sample example listed on the Getting Started page, it fails with the following error:
The name 'AspNetHost' does not exist in the current context
This occurs in StockTicker.cs here:
private static dynamic GetClients()
{
return AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<StockTickerHub>();
}
Can anyone explain what has become of AspNetHost?
Suggestions on how to get the SignalR.Sample compiling would be very welcome.
I had the same problem and found that this was deprecated in SignalR 0.5. Here is an article detailing the changes.
Specific to your item, the change is from this:
public void PerformLongRunningHubOperation()
{
var clients = AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<MyHub>();
clients.notify("Hello world");
}
To this in 0.5:
public void PerformLongRunningHubOperation()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.notify("Hello world");
}
You're gonna need to read the code because the source isn't in sync with the docs. The docs are for the current release, not the actively developed.
Take a look at the asp.net sample to see the current API. It's not set in stone yet though.

Categories