Error: System.Net.Http.HttpRequestException: Response status code does not indicate success: 405 (Method Not Allowed) - asp.net-core-3.1

I am getting following exception when calling an Asp.NET Core 3.1 web api from a Blazor app.
But same code works great from visual studio debugging
Response status code does not indicate success: 405 (Method Not Allowed).
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at Microsoft.AspNetCore.Components.HttpClientJsonExtensions.SendJsonAsync[T](HttpClient httpClient, HttpMethod method, String requestUri, Object content)*
UI Code:
public async Task<bool> UpdateCOAValue(COALookUps dataItem)
{
bool result = false;
try
{
bool response = await _httpClient.SendJsonAsync<bool>(HttpMethod.Put, string.Format(#_webApi.WebAPIUrl, "update"), dataItem);
result = await Task.FromResult(response);
}
catch (Exception ex)
{
Log.Error("Error: {0}", ex);
}
return result;
}
Web API Controller Method:
[HttpPut("update")]
public bool UpdateCOAEntry([FromBody]COALookups value)
{
try
{
List<SqlParameter> lstSQLParams = new List<SqlParameter>();
SqlParameter paramCOALookUpID = new SqlParameter();
//other code
dbManager.Update("UpdateCOALookUp", CommandType.StoredProcedure, lstSQLParams.ToArray());
}
catch (Exception ex)
{
Log.Error("Error: {0}", ex);
return false;
}
return true;
}
Web API Controllers syntax:
[Route("api/[controller]")]
[ApiController]
public class COAController : ControllerBase
{
}

Here is what worked for me. (this is a workaround), will have to redo this after each release. Please post if anyone has a better solution.
Open WebDav Authoring Rules and then select Disable WebDAV option
present on the right bar.
Select Modules, find the WebDAV Module and remove it.
Select HandlerMapping, find the WebDAVHandler and remove it.

I found this solution working than changing any settings in IIS
In ConfigureServices method add following
var handler = new HttpClientHandler()
{
UseDefaultCredentials = false,
Credentials = System.Net.CredentialCache.DefaultCredentials,
AllowAutoRedirect = true
};
services.AddSingleton(sp =>
new HttpClient(handler)
{
BaseAddress = new Uri(Configuration["WebAPI:BaseUrl"])
});

Related

Error handling Web Api .net core and Repository Pattern

I have question about web api and Repository may be its a duplicate question.
but i tried to search on it and i did not get any satisfactory answer.
In my Repository i am getting data with the help of httpclient.
My question is that i can get an error inside my response or i can get required json data which i can map to my product class.I am returning IEnumerable.
1) If i get an error how can i bubble it up to controller and display an error to user.
2) Return the MessageResponse instead of IEnumerable and handle it inside the controller.
What is the best way.
enter code here
public interface IProduct{
Task<IEnumerable<Product>> All();
}
public class Product:IProduct
{
public async Task<IEnumerable<Product>> All(){
var ResponseMessage=//some response.
}
}
You could customize a ApiException which is used to get the error message of the response, and call the UseExceptionHandler in your startup.cs ,refer to the following :
ProductRep
public class ProductRep : IProduct
{
private readonly HttpClient _client;
public ProductRep(HttpClient client)
{
_client = client;
}
public async Task<IEnumerable<Product>> All()
{
List<Product> productlist = new List<Product>();
var response = await _client.GetAsync("https://localhost:44357/api/values/GetProducts");
string apiResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode == false)
{
JObject message = JObject.Parse(apiResponse);
var value = message.GetValue("error").ToString();
throw new ApiException(value);
}
productlist = JsonConvert.DeserializeObject<List<Product>>(apiResponse);
return productlist;
}
public class ApiException : Exception
{
public ApiException(string message): base(message)
{ }
}
}
Startup.cs
app.UseExceptionHandler(a => a.Run(async context =>
{
var feature = context.Features.Get<IExceptionHandlerPathFeature>();
var exception = feature.Error;
var result = JsonConvert.SerializeObject(new { error = exception.Message });
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(result);
}));

Best practices to handle Web API status codes

I have a web API project done with .NETCore.
My web API receives a request from another Service A, with the information I have I need to do some conversion on the data and send it to another Service B.
I am expecting that Service B send back some response: like OK or NOK. As the number of codes I can get back from Service B are so much. I would like to know which is the best practices to handle those codes?
As you will see in my code, I get the status code in this way:
var status = (int)response.StatusCode;
And the I have some if to handle this. Looking at my code it looks like a very poor status code Handling but at moment it is the best I can do. I am kindly asking suggestions to improve this.
I am using RestSharp.
Following my code:
[HttpPost]
[Produces("application/json", Type = typeof(MyModel))]
public async Task<IActionResult> Post([FromBody]MyModel myModel)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var response = (RestResponse) await _restHelper.GetResponse("ServiceB:url", myModel);
if (response != null)
{
var status = (int)response.StatusCode;
//2xx status OK
if (status >= 200 && status < 300)
{
return Ok(response.Content);
}
//Catch all status code
return StatusCode(status, response.Content);
}
//If for some reason, I don't get any response from ServiceB
return NotFound("No response from ServiceB");
}
catch (Exception ex)
{
_logger.LogError("POST_ERROR", "ServiceB-relay/Post UNEXPECTED ERROR", ex.Message);
return StatusCode(500, "Server error, not able to process your request");
}
}
and this is my restHelper
public class RestHelper: IRestHelper
{
private readonly IConfigurationRoot _config;
public RestHelper(IConfigurationRoot config)
{
_config = config;
}
public async Task<IRestResponse> GetResponse(string configKey, object dtoObject)
{
//Get the URL from the config.json
var url = _config[configKey];
//Create rest client and rest request
var restClient = new RestClient(url);
var request = new RestRequest {Timeout = 30000, Method = Method.POST};
//Add header
request.AddHeader("Accept", "application/json");
//convert the dto object to json
var jsonObject = JsonConvert.SerializeObject(dtoObject.ToString(), Formatting.Indented);
request.AddParameter("application/json", jsonObject, ParameterType.RequestBody);
var taskCompletion = new TaskCompletionSource<IRestResponse>();
//Execute async
restClient.ExecuteAsync(request, r => taskCompletion.SetResult(r));
//await the task to finish
var response = (RestResponse) await taskCompletion.Task;
return response;
}
Thanks

Azure Mobile Apps Offline Client Throws NotSupportedException on Query

I have a Azure Mobile Apps Xamarin.Forms PCL client and have Offline Sync enabled. I tried to Pull data from my backend and afterwards query data from the offline storage with a Where clause. That throws the following exception and I don't know why.
Sync error: 'fahrerinfo.Imei.Equals("02032032030232")' is not supported in a 'Where' Mobile Services query expression.
public async Task SyncAsync()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
try
{
await OfflineSyncStoreManager.Instance.TruckFahrerTable.PullAsync("allTruckFahrerItems",
OfflineSyncStoreManager.Instance.TruckFahrerTable.CreateQuery());
Debug.WriteLine("SyncAsync: PUSH/PULL completed.");
}
catch (MobileServicePushFailedException e)
{
Debug.WriteLine("SyncAsync: PUSH failed.");
Debug.WriteLine(e.Message);
}
catch (Exception e)
{
Debug.WriteLine("SyncAsync: PUSH/PULL failed.");
Debug.WriteLine(e.Message);
//Debugger.Break();
}
}
public async Task<ObservableCollection<TruckFahrer>> GetTruckFaherAsync(bool syncItems)
{
try
{
if (syncItems)
{
await OfflineSyncStoreManager.Instance.SyncAsync().ConfigureAwait(false);
}
var deviceInfo = DependencyService.Get<IDeviceInfo>().GetPhoneInfo();
var imeiString = deviceInfo[trucker_rolsped.PhoneInfo.PhoneInfo.ImeiKey];
var imei = imeiString.Equals("000000000000000") ? deviceInfo[trucker_rolsped.PhoneInfo.PhoneInfo.IdKey] : imeiString;
IEnumerable<TruckFahrer> items =
await OfflineSyncStoreManager.Instance.TruckFahrerTable
//.Where(fahrerinfo => fahrerinfo.Imei.Equals(imei)) TODO: Why does that throw an exception???
.ToEnumerableAsync();
// TODO: Because above does not work
items = items.Where(fahrer => fahrer.Imei.Equals(imei));
return new ObservableCollection<TruckFahrer>(items);
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(#"Invalid sync operation: {0}", msioe.Message);
Debugger.Break();
}
catch (Exception e)
{
Debug.WriteLine(#"Sync error: {0}", e.Message);
Debugger.Break();
}
return null;
}
Thanks for any hint,
Eric
Are you a Java developer too? I'm and had this issue because in Java we need to compare strings with String#equals method, haha.
For some reason MobileServices doesn't allow us to use Equals in this situation.
To fix your problem, use == instead. As you can see here C# difference between == and Equals() both have the same effect in this case.
Where(fahrerinfo => fahrerinfo.Imei == imei)

Xamarin.Auth fails to complete with Trakt

I'm building an app as Trakt client using Xamarin. To authenticate users, I use Xamarin.Auth because its cross-platform. However, after the authentication succeeds, it doesn't call Completed event handler. The event is only called once I click on the Back button but it returns a null Account object and false IsAuthenticated.
I'm wondering if its because the redirect uri is invalid.
Please see my code below.
[assembly: ExportRenderer(typeof(LoginView), typeof(LoginViewRenderer))]
namespace ShowsCalendar.Droid.ViewRenderer
{
public class LoginViewRenderer : PageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
var context = Forms.Context;
var baseAddress = ConfigHelper.TraktAPIURL;
var auth = new OAuth2Authenticator(
clientId: ConfigHelper.ClientID,
redirectUrl: new Uri("urn:ietf:wg:oauth:2.0:oob"),
scope: "",
authorizeUrl: new Uri(baseAddress + "/oauth/authorize?response_type=code")
);
auth.AllowCancel = true;
auth.Completed += AuthenticateCompleted;
var intent = auth.GetUI(context);
context.StartActivity(intent);
}
private void AuthenticateCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
if (!e.IsAuthenticated)
{
return;
}
App.AccessToken = e.Account.Properties["access_token"].ToString();
AccountStore.Create().Save(e.Account, "Trakt");
}
}
}

MVC 2.0 - Custom handling of all errors to return json

I have an MVC 2 app that I want all requests to return json. I have overridden a HandleErrorAttribute and an AuthorizeAttribute. My goal is that all errors (even 403 and 404) are returned as json.
Here is my error handler. ExceptionModel is a simple class defining any error returned by my application. The Exception handler is a class that translates the error details into a formatted e-mail and sends it to me.
public class HandleErrorJsonAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
context.ExceptionHandled = true;
RaiseErrorSignal(context.Exception);
context.RequestContext.HttpContext.Response.ContentType = "application/json";
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(context.HttpContext.Response.Output, new ExceptionModel(context.Exception));
}
private static void RaiseErrorSignal(Exception ex)
{
IExceptionHandler handler = Resolve();
handler.HandleError(ex.GetBaseException());
}
private static IExceptionHandler Resolve()
{
return ServiceLocator.Locate<IExceptionHandler>();
}
}
Here is the Exception model for clarification
public class ExceptionModel
{
public int ErrorCode { get; set; }
public string Message { get; set; }
public ExceptionModel() : this(null)
{
}
public ExceptionModel(Exception exception)
{
ErrorCode = 500;
Message = "An unknown error ocurred";
if (exception != null)
{
if (exception is HttpException)
ErrorCode = ((HttpException)exception).GetHttpCode();
Message = exception.Message;
}
}
public ExceptionModel(int errorCode, string message)
{
ErrorCode = errorCode;
Message = message;
}
}
and finally, my custom authorize attribute. I an using forms auth, but I did not want any of the automatic redirection. I simply want the error to show on the screen and stop any further processing.
public class AuthorizeTokenAttribute : System.Web.Mvc.AuthorizeAttribute
{
public bool SuperAdminOnly { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = base.AuthorizeCore(httpContext);
if(!SuperAdminOnly)
return authorized;
if(!authorized)
return authorized;
return SessionHelper.UserIsSuperAdmin(httpContext.User.Identity.Name);
}
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
throw new HttpException(403, "Access Denied");
}
}
This all works great for most errors, but it is missing one thing. I have a controller action like this.
[AuthorizeToken]
[HttpPost]
public JsonResult MyAction()
{
return new JsonResult();
}
It works fine when you submit via post, but on a get I receive an unhandled 404 error.
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource
you are looking for (or one of its
dependencies) could have been removed,
had its name changed, or is
temporarily unavailable. Please
review the following URL and make sure
that it is spelled correctly.
Requested URL: /MyController/MyAction
Version Information: Microsoft .NET
Framework Version:4.0.30319; ASP.NET
Version:4.0.30319.1
This happens on a GET, which is to be expected as default behavior. However, how can I handle for this condition so that I could instead return json like this
{"ErrorCode":404,"Message":"Page Not Found"}
To handle errors personally I prefer the Application_Error event in Global.asax:
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
Response.Clear();
Server.ClearError();
var httpException = exception as HttpException;
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "Index";
routeData.Values["error"] = exception;
IController errorController = new ErrorsController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
and then have an ErrorsController:
public class ErrorsController : Controller
{
public ActionResult Index(Exception exception)
{
var errorCode = 500;
var httpException = exception as HttpException;
if (httpException != null)
{
errorCode = httpException.ErrorCode;
}
return Json(new
{
ErrorCode = errorCode,
Message = exception.Message
}, JsonRequestBehavior.AllowGet);
}
}