Problem with call Controller from Angular - c#

I have a problem with running Controller from angular ClientApp service.
Cannot understand why Controller has not got any calls.
My angular service code:
export class MediaService extends BaseService {
constructor(private http: Http, configService: ConfigService) {
super(configService);
}
getMedia(mediaId: string) {
return this.http
.get(
'api/media',
{
params: {
id: mediaId
},
headers: this.getBaseHttpHeaders()
}).map(result => {
return result.json();
})
.map(result => {
if (result.status === 1) {
return { success: true, data: result.data };
}
else {
return { success: false, data: result.data };
}
});
}
MediaController.cs
[Authorize(Policy = "UserExists")]
[Produces("application/json")]
[Route("api/media")]
public class MediaController : BaseController
{
private readonly IMediaService _mediaService;
private readonly ICollectionPhotosService _collectionPhotosService;
public MediaController(IUserService userService, IMediaService mediaService, ICollectionPhotosService collectionPhotosService) : base(userService)
{
_mediaService = mediaService;
_collectionPhotosService = collectionPhotosService;
}
[HttpGet]
public IActionResult Index(string id, string collectionPhotoId = null)
{
try
{
Guid guidId = Guid.Empty;
Guid collectionPhotoGuidId = Guid.Empty;
if ((!Guid.TryParse(id, out guidId) && collectionPhotoId == null) || (!Guid.TryParse(collectionPhotoId, out collectionPhotoGuidId) && id == null))
{
return NotFound();
}
if (string.IsNullOrWhiteSpace(UserId))
{
return GenerateBadResult("Incorrect user");
}
var isItemMedia = guidId != Guid.Empty;
return isItemMedia ? HandleMediaItem(guidId, UserId) : HandleCollectionPhotoItem(collectionPhotoGuidId, UserId);
}
catch (Exception)
{
return GenerateBadResult("Some error occured");
}
}
BaseService.cs
public class BaseController : Controller
{
protected readonly IUserService _userService;
public BaseController(IUserService userService)
{
_userService = userService;
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
DbInitializer.AdminV2Initialize(Configuration.GetConnectionString("DefaultConnection"));
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
services.Configure<SmtpClientConfig>(Configuration.GetSection(nameof(SmtpClientConfig)));
services.TryAddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<ITokenService, TokenService>();
services.AddScoped<IEmailProvider, EmailProvider>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<IMediaService, MediaService>();
services.AddScoped<ICollectionService, CollectionService>();
services.AddScoped<IEmailService, EmailService>();
services.AddScoped<ILocationService, LocationService>();
services.AddScoped<ICollectionPhotosService, CollectionPhotosService>();
services.AddSingleton<IUserDataCSVGenerator, UserDataCSVGenerator>();
I also have AuthController which works fine.
And when I'm using MediaController I have only 500 Internal Server Error (
Controller not even try to Initialize - what the problem?

Related

My ASP.NET Core's ApiController is not functional - JS Fetch returns 404

So I have my endpoint defined like the following:
[ApiController]
[Route("load/stuff")]
public class SignUp : ControllerBase
{
IGoogleRecaptchaV3Service _gService { get; set; }
public SignUp(IGoogleRecaptchaV3Service gService)
{
_gService = gService;
}
[HttpPost]
public async Task<IActionResult> Post([FromQuery] SignUpModel SignUpData, GRequestModel.Factory grequestFactory)
{
GRequestModel grm = grequestFactory("resValue", "remipValue");
_gService.InitializeRequest(grm);
if (!await _gService.Execute())
{
//return error codes string.
return Ok(_gService.Response.error_codes);
}
//call Business layer
return base.Content("Content here", "text/html");
}
}
This should return the HTML content if the reCAPTCHA score is human-like.
Let me know how to debug this further and whether any further code is required.
UPDATE fetch JS Code
function loadStuff() {
if (location.pathname === "/test") {
grecaptcha.execute('recaptchasitekeyhere', { action: 'onloadafterdelay' }).then(function (token) {
console.log(token);
return fetch("/load/stuff?RecaptchaToken=" + token, {
method: "POST",
body: token,
})
}).then((response) => {
// console.log works here too
if (!response.ok) {
const errorBuild = {
type: "Error",
message: response.message || "Something went wrong",
data: response.data || "",
code: response.code || "",
};
console.log("Error: " + JSON.stringify(errorBuild));
}
response.text().then(body => {
//console.log(body);
document.getElementById("test1").innerHTML = body.split(' ')[0];
document.getElementById("test2").innerHTML = body.split(' ')[1];
});
}
)
}
}
I also added this in the program.cs file:
builder.Services.AddControllers();
// FIX TEST
builder.Services.AddTransient<GRequestModel.Factory>(serviceProvider =>
(string res, string remip) => new GRequestModel(serviceProvider.GetRequiredService<IConfiguration>(), res, remip));
//Register dependencies
builder.Services.AddRazorPages();
// REMOVE ME IN PRODUCTION, USE DI INSTEAD
// ....
Configuration = app.Configuration;
// ...
public partial class Program
{
internal static IConfiguration Configuration { get; private set; }
}
I added that code above as a temporary fix, but then I tried to implement dependency injection for the IConfiguration and my codebase got dirty. I'm still a beginner in C# and I'm learning by trial and error hence so many mistakes.

Swashbuckle add custom header to some methods only

I have successfully add custom header using IOperationFilter in my .net core application, now my problem is how to filter it out for certain methods only in the SomeController class. Is this achievable? This is my current code:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
// some swagger services here.
c.OperationFilter<SomeFilter>();
});
}
SomeFilter.cs
public class SomeFilter: IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
operation.Parameters = new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = "Some-Custom-Header",
In = ParameterLocation.Header,
Required = false,
Schema = new OpenApiSchema
{
Type = "String"
}
});
}
}
SomeController.cs
[ApiController]
[Route("[controller]")]
public class SomeController: Controller
{
[AllowAnonymous]
[HttpPost("some_method1")]
public IAction SomeMethod1() // this method should not include custom header filter
{
return Ok();
}
[Authorize]
[HttpPost("some_method2_with_authorize")]
public IAction SomeMethod2() // this should have the custom header in swagger
{
return Ok();
}
[AllowAnonymous]
[HttpGet("some_method3_without_authorize")]
public IAction SomeMethod3() // this should have the custom header in swagger
{
return Ok();
}
}
I found a way on how to exclude the method that will exclude the said methods by doing this:
public class SomeFilter: IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var methodName = context.ApiDescription.ActionDescriptor.As<ControllerActionDescriptor>().ActionName;
var hasExcludedMethod = ApiFilterSettings.AppSettingsFilterMethods.ToStringList().Contains(methodName);
if(hasExcludedMethod)
return; // return directly when an excluded method is found;**strong text**
if (operation.Parameters == null)
operation.Parameters = new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = "Some-Custom-Header",
In = ParameterLocation.Header,
Required = false,
Schema = new OpenApiSchema
{
Type = "String"
}
});
}
}
I hope this will help you guys.

posting with js to api (asp.net core mvc )

Hello im using a DTO for a single value(Id) & trying to post to Db using ApiController but on button click I keep getting error 400 that is referring me to xhr.send error.
(im using asp.net core 2.1 )
Code :
#section Scripts{
<script type="text/javascript">
$(document)
.ready(function() {
$(".js-toggle-HandShake")
.click(function(e) {
var button = $(e.target);
console.log(button.attr("data-QuettaOfferId")); //Value=24 >> OK
$.post("/Api/HandShake/", { QuettaOfferId: button.attr("data-QuettaOfferId") })
// Error in > POST https://localhost:44339/Api/HandShake/ 400 () &
//in jquery>> xhr.send( options.hasContent && options.data || null );
.done(function() {
button
.text("Chousen");
})
.fail(function() {
alert("Something failed");
});
});
});
</script>
}
& the ApiController code
[Microsoft.AspNetCore.Mvc.Route("api/[controller]")]
[ApiController]
[Microsoft.AspNetCore.Authorization.Authorize]
public class HandShakeController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityUser> _userManager;
// private readonly IHostingEnvironment hostingEnvironment;
public HandShakeController(ApplicationDbContext context ,UserManager<IdentityUser> userManager/*, IHostingEnvironment environment*/)
{
_context = context;
_userManager = userManager;
//hostingEnvironment = environment;
}
[Microsoft.AspNetCore.Mvc.HttpPost]
// public IHttpActionResult HandShakes(HandShakeDto dto)
public IActionResult HandShakes(HandShakeDto dto)
{
var userId = _userManager.GetUserId(User);
var check = _context.Quetta.Where(u => u.SiteUserId == userId);
if ( _context.handShakes.Any(f => f.QuettaOfferId == dto.QuettaOfferId))
return BadRequest("Some error Msg");
if (check.Any())
{
var hand = new HandShake
{
QuettaOfferId = dto.QuettaOfferId
};
try
{
_context.handShakes.Add(hand);
_context.SaveChangesAsync();
return Ok();
}
catch (Exception e)
{
Console.WriteLine(e);
return BadRequest("Some error Msg");
}
}
else{
return BadRequest("");}
// Check if the user id that publish the ed = login user.
//if so add the offer to selected table,
}
}
im using asp.net core 2.1 & strongly suspect that the problem is in the ApiController but im not sure.
The DTO
public class HandShakeDto
{
public int QuettaOfferId { get; set; }
}
Try replacing
$.post("/Api/Hand/", { QuettaOfferId: button.attr("data-QuettaOfferId") })
By
$.post("/Api/HandShake/", { QuettaOfferId: button.attr("data-QuettaOfferId") })
as your api controller name is HandShakeController

My data does not pass through to controller from Typescript view? I am using angular 5 .net core apllication 2.0

Here is my code for Method in TypeScript
Ive been trying to pass an number[] array to the controller to send to a quickbooks api but all i really need right now is to get the values into the controller,
This is been done in Angular 5 .net core 2.0 latest version
The data hits the Post Method with no error and i have breakpoints everywhere it never reaches the controller.
import { Injectable } from '#angular/core';
import { Customer } from '../models/customer';
import { Vendor } from '../models/vendor';
import { Item } from '../models/item';
import { Invoice } from '../models/invoice';
import { CreditNote } from '../models/creditNote';
import { PPO } from '../models/ppo';
import { PO } from '../models/po';
import { AppSettings } from '../models/appSettings';
import { Http, Response, Headers, RequestOptions, RequestMethod, URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { MsgResult } from '../models/msgResult';
import { Router, ActivatedRoute } from '#angular/router';
import { isPlatformBrowser, isPlatformServer } from '#angular/common';
#Injectable()
export class SyncDataService {
errorMessage: string = "";
baseURL: string = 'http://localhost:56199/api';
constructor(private _http: Http, private route: ActivatedRoute, private router: Router) {}
syncCustomers(ids: Array<number>) {
var headers = new Headers();
headers.append('Content-Type', 'application/json; charset=utf-8');
var localStorage1 = localStorage.getItem('access_token');
if (localSt
orage1 != undefined) {
var token = JSON.parse(localStorage1);
//headers.append('Authorization', 'bearer ' + token);
//return this._http.post(this.baseURL + '/customer', ids, options)
// .map((response: Response) => <string>response.json())
// .catch(err => {
// return this.handleError(err);
// });
var stringids = JSON.stringify({ customerIDs: ids });
this._http.post(this.baseURL + '/customer/PostCust',
stringids).subscribe(result => result.json()), err => {
return this.handleError(err);
}
}
}
}
Here is my controller
[Route("api/[controller]")]
public class CustomerController : Controller
{
private readonly SyncDbContext _dbContext;
public CustomerController(SyncDbContext dbContext)
{
_dbContext = dbContext;
}
[HttpGet]
public List<Customer> Get()
{
return new SyncDataManager().GetCustomers();
}
[HttpPost("[action]")]
[AllowAnonymous]
public JsonResult PostCust([FromBody]int[] customerIDs)
{
// call quicbooks api and pass them the customers
// once quickbooks verifys the customer and sends us back a reference
// pass the quickbooks customer to SyncDataManager
var sync = new SyncDataManager();
var results = sync.UpdateCustomers(customerIDs);
var failedResults = results.Where(m => m.Success == false).ToList();
if(failedResults.Count == 0)
{
var json = new JsonResult("Updated Successfully");
json.StatusCode = 200;
return json;
}
else
{
var error = new StringBuilder();
foreach (var errorMessage in failedResults)
{
//string output = errorMessage.ErrorMessage.Substring(errorMessage.ErrorMessage.IndexOf('.') + 1);
string output = errorMessage.ErrorMessage;
error.AppendLine(output);
}
var json = new JsonResult(error.ToString());
json.StatusCode = 400;
return json;
}
}
There is no error messages and when i use break points on my controller, It does not hit the break points, been at it for 3 days no break through Please help
try in your Controller
[Route("api/[controller]/[action]")] //<--include action
public class CustomerController : Controller
{
...
[HttpGet,ActionName("Get")] //<--I don't know if it's necesary
public List<Customer> Get() {..}
[HttpPost, ActionName("PostCust")] //<--give there the "actionName
[AllowAnonymous]
public JsonResult PostCust([FromBody]int[] customerIDs){...}
}
this._http.post(this.baseURL + '/customer/PostCust',
this.customerIDs).subscribe((data:Response) => { this.resu = (data.json() as string) },
error => {
alert(error.json());
},
() => {
alert("Completed");
} else {
this.RefreshCustomers();
}
});
this.resu is my results variable
and no headers or casts for this.customerIDs this worked for me

AuthorizationHandler exception not going through ExceptionFilter

I have an application in ASP.NET Core MVC (dnx46) RC1 with an AuthorizationHandler:
public class AppSumAuthAuthorizationHandler : AuthorizationHandler<AppSumAuthRequirement>
{
private readonly IUserRepository _userRepository;
private readonly IUserRoleRepository _userRoleRepository;
public AppSumAuthAuthorizationHandler(IUserRepository userRepository, IUserRoleRepository userRoleRepository)
{
_userRepository = userRepository;
_userRoleRepository = userRoleRepository;
}
protected override async void Handle(AuthorizationContext context, AppSumAuthRequirement requirement)
{
await HandleAsync(context,requirement);
}
protected override async Task HandleAsync(AuthorizationContext context, AppSumAuthRequirement requirement)
{
var currentUserName = context.User.Identity.Name;
var currentUser = await _userRepository.GetAsync(u => u.UserName == context.User.Identity.Name);
// Create user that does not yet exist
if(currentUser == null)
{
var user = new User(currentUserName);
/* Temporary add SysAdmin role */
using(new CreatedBySystemProvider(_userRepository))
{
_userRepository.Add(user);
await _userRepository.SaveChangesAsync();
if (string.Equals(currentUserName, #"BIJTJES\NilsG", StringComparison.CurrentCultureIgnoreCase))
{
user.AddRole(1);
}
currentUser = await _userRepository.GetAsync(u => u.Id == user.Id);
}
}
var resource = (Microsoft.AspNet.Mvc.Filters.AuthorizationContext) context.Resource;
var controllerActionDescriptor = resource.ActionDescriptor as ControllerActionDescriptor;
var controllerName = controllerActionDescriptor.ControllerName;
var actionName = controllerActionDescriptor.Name;
string moduleName;
try
{
// Get the name of the module
moduleName = ((ModuleAttribute)controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(false).First(a => a.GetType().Name == "ModuleAttribute")).ModuleName;
}
catch(InvalidOperationException ex)
{
context.Fail();
throw new InvalidOperationException($"The Module Attribute is required on basecontroller {controllerName}.", ex);
}
var access = new Access(moduleName, controllerName, actionName);
if (await currentUser.HasPermissionTo(UrlAccessLevel.Access).OnAsync(access))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
The requirement class is empty:
public interface IAppSumAuthRequirement : IAuthorizationRequirement
{
}
public class AppSumAuthRequirement : IAppSumAuthRequirement
{
}
The Module attribute is also nothing special:
public class ModuleAttribute : Attribute
{
public string ModuleName { get; private set; }
public ModuleAttribute(string moduleName)
{
ModuleName = moduleName;
}
public override string ToString()
{
return ModuleName;
}
}
The exception filter:
public class JsonExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var exception = context.Exception;
context.HttpContext.Response.StatusCode = 500;
context.Result = new JsonResult(new Error
{
Message = exception.Message,
InnerException = exception.InnerException?.InnerException?.Message,
Data = exception.Data,
ErrorCode = exception.HResult,
Source = exception.Source,
Stacktrace = exception.StackTrace,
ErrorType = exception.GetType().ToString()
});
}
}
and policy are configured in my Startup.cs:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new JsonExceptionFilterAttribute());
options.ModelBinders.Insert(0, new NullableIntModelBinder());
}).AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
});
// Security
services.AddAuthorization(options =>
{
options.AddPolicy("AppSumAuth",
policy => policy.Requirements.Add(new AppSumAuthRequirement()));
});
}
and the policy is set on all controllers, by inheriting BaseController:
[Authorize(Policy = "AppSumAuth")]
public class BaseController : Controller
{
public BaseController()
{
}
}
So, in my handler, I get the controllername, actionname and modulename (from the attribute set on the controllers):
[Module("Main")]
When this attribute is not set on a controller, I would like to catch the exception and report this back to the developer calling the controller and deny access. To do this, I've added:
catch(InvalidOperationException ex)
{
context.Fail();
throw new InvalidOperationException($"The Module Attribute is required on basecontroller {controllerName}.", ex);
}
The JsonExceptionFilter is called perfectly when there is an exception in the controllers. It is however not called when there is an error in the AuthorizationHandler.
So the question:
How can I get the Exceptions to be caught by the JsonExceptionFilter?
What am I doing wrong?
Solution:
Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// For Windows Auth!
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseExceptionHandler(AppSumExceptionMiddleware.JsonHandler());
app.UseMvc();
}
And my middleware:
public class AppSumExceptionMiddleware
{
public static Action<IApplicationBuilder> JsonHandler()
{
return errorApp =>
{
errorApp.Run(async context =>
{
var exception = context.Features.Get<IExceptionHandlerFeature>();
if (exception != null)
{
var exceptionJson = Encoding.UTF8.GetBytes(
JsonConvert.SerializeObject(new AppSumException(exception.Error),
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
})
);
context.Response.ContentType = "application/json";
await context.Response.Body.WriteAsync(exceptionJson, 0, exceptionJson.Length);
}
});
};
}
}
Action filter can be used as a method filter, controller filter, or global filter only for MVC HTTP requests. In your case you need to use a middleware, as
Middleware is component that "sit" on the HTTP pipeline and examine
all requests and responses.
As you want to works with exception, you may use ready-to-use ExceptionHandler middleware:
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = 500; // for example
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
var ex = error.Error;
// custom logic
}
});
});

Categories

Resources