Angular service function is undefined - MVC6 - c#

I am trying to write a login service (in typescript), which posts the username and password to my C# controller. The C# controller then makes a service call that hits my database to authenticate the user, but that is out of scope for this question.
The issue is that when I try to call my authentication function (which is found in my angular service) from my angular controller, I get an error in my console that it is unable to get property 'Authenticate' of undefined or null reference.
Here is the base class (Handler) for my services:
module app.Services {
export class HttpHandlerService {
httpService: ng.IHttpService;
handlerUrl: string;
constructor($http: ng.IHttpService) {
super();
this.httpService = $http;
}
useGetHandler(params: any): ng.IPromise<any> {
var result: ng.IPromise<any> = this.httpService.get(this.handlerUrl, params)
.then((response: any): ng.IPromise<any> => this.handlerResponded(response, params));
return result;
}
usePostHandler(params: any): ng.IPromise<any> {
var result: ng.IPromise<any> = this.httpService.post(this.handlerUrl, params)
.then((response: any): ng.IPromise<any> => this.handlerResponded(response, params));
return result;
}
handlerResponded(response: any, params: any): any {
response.data.requestParams = params;
return response.data;
}
}
}
Then my login service inherits it:
module app.Services {
export interface ILoginService {
Authenticate(email: string, password: string): ng.IPromise<any>;
}
export class LoginService extends Services.HttpHandlerService {
static $inject = ['$http'];
constructor($http: ng.IHttpService) {
this.handlerUrl = '/Login';
super($http);
}
// Authentication function I am attempting to call
Authenticate(email: string, password: string): ng.IPromise<any> {
// I have not completed the actual request that is being sent
var config: any = {};
var request = {
"Email": email,
"Password": password
}
return this.usePostHandler(config);
}
}
angular.module('App').factory('loginService', LoginService);
}
Here is my login controller where I'm calling the service:
module app.Login {
import Services = app.Services;
interface ILoginController {
email: string;
password: string;
login(): void;
}
class LoginController implements ILoginController{
email: string;
password: string;
loginService: Services.ILoginService;
loginForm: any;
static $inject = ["$state"];
constructor(private $state: ng.ui.IStateParamsService, loginService: Services.ILoginService) {
this.email = "";
this.password = "";
this.loginService = loginService;
}
login() {
if (this.loginForm.$invalid) {
return;
}
var request = this.loginService.Authenticate(this.email, this.password);
request.success(function (data) {
console.log("User authenticated.");
});
request.error(function () {
console.log("Error: User not authenticated.");
});
}
}
angular.module('App').controller('loginController', LoginController);
}
And finally my c# controller"
[HttpPost]
[Route("/Login")]
public async Task<IActionResult> Login()
{
// . . . .
}
Any help would be appreciated. Let me know if you need more information.
EDIT:
This is the javascript generated from the login service typescript:
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var app;
(function (app) {
var Services;
(function (Services) {
var LoginService = (function (_super) {
__extends(LoginService, _super);
function LoginService($http) {
this.handlerUrl = '/Login';
_super.call(this, $http);
}
LoginService.prototype.Authenticate = function (email, password) {
var config = {};
var request = {
"Email": email,
"Password": password
};
return this.usePostHandler(config);
};
LoginService.$inject = ['$http'];
return LoginService;
})(Services.HttpHandlerService);
Services.LoginService = LoginService;
angular.module('App').factory('loginService', LoginService);
})(Services = app.Services || (app.Services = {}));
})(app || (app = {}));
I do get an error, only in IE, that _super is undefined.

Unable to get property 'Authenticate' of undefined or null reference. means that this.loginService was not properly injected by Angular.
You can try changing this:
static $inject = ["$state"];
to this:
static $inject = ["$state", "LoginService"];
Proper Dependency Injection in Your AngularJS TypeScript Apps

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.

Get Data From Post Request Angular/.NET Core

I'm having trouble getting a JSON response from a POST Request from my .Net Core server. In essence I would be using this POST request like a GET request from the server. I believe I'm passing in the correct headers, however, in my console error I'm getting
ERROR TypeError: Cannot read property 'sessionId' of undefined
I suspect it's something that has to do with the type and/or model. Or possibly how I'm calling it in the service. If I need to add anything for clarification, lmk.
.NET CORE Server Code
Action.Dto
{
public class ActionDto
{
public string SessionId { get; set; }
public Tag ActionTag { get; set; }
public ActionParams Args { get; set; }
}
}
ActionService.cs
{
ActionResponse LaunchAction(string sessionId, Tag actionTag, ActionParams args, UserState userState);
}
Action Controller
public IActionResult LaunchAction([FromBody]ActionDto launchActionParameters)
{
var sessionId = launchActionParameters.SessionId;
var actionTag = launchActionParameters.ActionTag;
var args = launchActionParameters.Args;
UserState userState = null;
RunAction runAction = null;
Angular Client Code
Action Component
export interface ActionView {
actionName: string;
actionType: string;
primaryTable: string;
specialUse: string;
folder: string;
actionDescription: string;
actionTag: number;
chartType: string;
priority: number;
}
const ACTION_DATA: ActionView[] = [];
#Component({
templateUrl: 'home.component.html'
})
export class HomeComponent implements OnInit, OnDestroy {
// User Fields
currentUser: User;
users: User[] = [];
currentUserSubscription: Subscription;
// Action Fields
currentAction: Action;
actions: Action[] = [];
displayedColumns: string[] =
['actionName', 'actionType', 'primaryTable', 'specialUse',
'folder', 'actionDescription', 'actionTag', 'chartType',
'priority'];
dataSource: any = new MatTableDataSource(ACTION_DATA);
constructor(
private authenticationService: AuthenticationService,
private iconRegistry: MatIconRegistry,
private sanitizer: DomSanitizer,
private httpClient: HttpClient,
private actionService: ActionService
) {
this.currentUserSubscription = this.authenticationService.currentUser.subscribe(user => {
this.currentUser = user;
});
this.iconRegistry.addSvgIcon(
'thumbs-up',
this.sanitizer.bypassSecurityTrustResourceUrl('assets/img/examples/thumbup-icon.svg'));
}
#ViewChild(MatSort) sort: MatSort;
public getActions() {
console.log('test');
this.actionService.getActions(
this.currentAction).subscribe((data) => {
this.dataSource = data;
});
}
ngOnInit() {
this.dataSource.sort = this.sort;
this.getActions();
}
ngOnDestroy() {
// unsubscribe to ensure no memory leaks
this.currentUserSubscription.unsubscribe();
}
}
Action Service
#Injectable({ providedIn: 'root' })
export class ActionService {
public apiURL = 'http://localhost:15217/api';
public currentUser: Observable<User>;
public currentAction: Observable<Action>;
constructor(private http: HttpClient) { }
// Http Options
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
getActions(action: Action): Observable<Action[]> {
return this.http.post<Action[]>(this.apiURL + '/actions/launchactions',
{
sessionId: action.sessionId,
tag: action.actionTag,
actionParams: action.actionParams
})
.pipe(
retry(1),
catchError(this.handleError)
);
}
// Error handling
handleError(error: any) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// Get client-side error
errorMessage = error.error.message;
} else {
// Get server-side error
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
window.alert(errorMessage);
return throwError(errorMessage);
}
add [FromBody] to controller side service, before the parameter. Post method pass parameters in body.
like
ActionResponse LaunchAction([FromBody]string sessionId, [FromBody]Tag actionTag, [FromBody]ActionParams args, [FromBody]UserState userState);
I don't know why microsoft did not decide to do this default.
You should remove {} from data: {}
By doing this you are assigning an empty object to that
What if you remove the "params" word from your angular http post call ?
So the http post call is this instead
return this.http.post<Action[]>(this.apiURL + '/actions/launchactions',
{
sessionId: action.sessionId,
tag: action.actionTag,
actionParams: action.actionParams
})
.pipe(
retry(1),
catchError(this.handleError)
);

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

ASP.NET Core 2.0 Web API Receiving/Sending Json requests from ionic 3

I have an ASP.NET Core 2.0 Web API Integrated with ionic 3.
I'm having problems receiving JSON data sent from ionic 3 App, Here is sample code:-
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { AlertController, LoadingController } from 'ionic-angular';
import { FCM } from '#ionic-native/fcm';
#Injectable()
export class ServerProvider {
private baseurl = "http://localhost:9681/api";
private api: String[] = new Array();
public loader: any;
constructor(public fcm: FCM, public http: Http, public alertCtrl:
AlertController, public loadingCtrl: LoadingController) {
this.api['auth'] = 'Authentication';
this.api['agency'] = 'Agencies';
this.api['user'] = 'Users';
this.api['route'] = 'Routes';
this.api['token'] = 'Tokens';
this.api['notification'] = 'Notifications';
this.api['salepoint'] = 'Salepoints';
}
ServerRequest(api, request, data) {
return new Promise((resolve) => {
let headers = new Headers();
headers.append('Content-Type', 'application/json; charset=UTF-8');
this.http.get(this.baseurl + "/" + this.api[api] + "/", {headers: headers}).map(res => res.json()).subscribe((result) => {
resolve(result);
console.log(result);
}, (error) => {
console.log(error); this.CreateAlert("Error", error, [
{
text: 'Close',
handler: () => {
this.loader.dismiss();
}
}
]);
}, () => {
this.loader.dismiss();
});
});
}
Backend:-
[Route("api/Authentication")]
public class AuthenticationController : Controller
{
IConfiguration _configuration;
public AuthenticationController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public JsonResult GetUser(JsonResult json)
{
AgencyUsers agencyusers = new AgencyUsers(_configuration);
return Json(agencyusers.GetUser(json));
}
}
I receive the following error:-
An unhandled exception occurred while processing the request.
InvalidOperationException: Could not create an instance of type
'Microsoft.AspNetCore.Mvc.JsonResult'. Model bound complex types must
not be abstract or value types and must have a parameterless
constructor.
What is the correct way to receive (serialize and deserialize JSON) and send back JSON (data or errors)?
After a lot of digging and modifications, I have finally got the API to work fine.
In case someone ran into a problem similar to mine, Here what I did:-
At Ionic, I have changed the HTTP request from GET to POST.
ServerRequest(api, request, data) {
return new Promise((resolve) => {
let headers = new Headers();
headers.append('Content-Type', 'application/json; charset=UTF-8');
this.http.post(this.baseurl + "/" + this.api[api] + "/" + request, JSON.stringify(data),{headers:headers}).map(res => res.json()).subscribe((result) => { ... });}
At Backend, Used newtonsoft (JObject) Which saved me a lot of head that JsonResult causes, Then Changed Method type to IActionResult.
[HttpPost("GetAgencyUser")]
public IActionResult GetAgencyUser([FromBody]JObject request)
{
try
{
if (request["id"] == null)
{
return Ok("id is not defined or incorrect JSON format");
}
AgencyUsersMethods agencyusers = new AgencyUsersMethods(_configuration);
var result = agencyusers.GetAgencyUser(request);
if (result == null)
{
return Ok("User not Found");
}
else
{
return Ok(result);
}
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}

CSRF on singlepage using Web Api 2 backend

I'm trying to implement CSRF using AntiForgeryToken from .Net Framework on a single page application. I've implemented some code inside my .csthml file and i've created an AuthorizeAttribute:
Index.cshtml
<script>
#functions{
public string GetAntiForgeryToken()
{
string cookieToken, formToken;
System.Web.Helpers.AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
var xxx = '#GetAntiForgeryToken()';
jqXHR.setRequestHeader("X-CSRF", xxx);
});
</script>
ValidateHttpAntiForgeryTokenAttribute.cs
public class ValidateHttpAntiForgeryTokenAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var headers = actionContext.Request.Headers;
var headerToken = headers.Contains("X-CSRF") ? headers.GetValues("X-CSRF").FirstOrDefault() : null;
if (headerToken == null)
{
return false;
}
var tokenValues = headerToken.Split(':');
if (tokenValues.Length < 2)
{
return false;
}
else
{
var cookieToken = tokenValues[0];
var formToken = tokenValues[1];
try
{
AntiForgery.Validate(cookieToken, formToken);
}
catch(Exception ex)
{
return false;
}
}
return base.IsAuthorized(actionContext);
}
}
MyController.cs
[HttpGet]
[ValidateHttpAntiForgeryTokenAttribute]
public HttpResponseMessage Get()
{
...
}
Every time that ValidateHttpAntiForgeryTokenAttribute is called, i got the following error:
The provided anti-forgery token was meant for user "CMP\usr", but the current user is "dev#company.net"
I would like to know why it displays the username of computer instead the username that is logged on application and why the token isn't changing when call GetAntiForgeryToken() is executed.
Thank in advance.
As quick fix (if you don't care about username validation inside anti-CSRF logic) would be:
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
somewhere in AppStart logic (global.asax).

Categories

Resources