We are trying to implement a custom service using aspnetboilerplate .NET Core Multi Page Application template. We are receiving an error in index.js file when trying to hit a service method.
Find herewith the code sections for understanding. Any help on this will be really helpful for us.
public interface IMyTaskAppService : IApplicationService
{
Task<List<string>> GetMyTasks(int input);
}
public class MyTaskAppService : IMyTaskAppService
{
private readonly IMyTaskRepository _mytaskRepository;
public MyTaskAppService(IMyTaskRepository mytaskRepository)
{
_mytaskRepository = mytaskRepository;
}
Task<List<string>> IMyTaskAppService.GetMyTasks(int input)
{
return _mytaskRepository.GetMyTasks(input);
}
}
Index.Js
Index.Js Error (Lowercase)
Console Output Screenshot
MyTaskAppService requires at least one public method:
public class MyTaskAppService : IMyTaskAppService
{
// ...
// Task<List<string>> IMyTaskAppService.GetMyTasks(int input)
public Task<List<string>> GetMyTasks(int input)
{
return null;
}
}
What you have is an explicit implementation that is "more restricted than private".
Service and method names are in camelCase for Client Proxies.
Use an uppercase T for myTask:
var _myTaskService = abp.services.app.myTask;
Use a lowercase g for getMyTasks:
_myTaskService.getMyTasks({
taskID: taskID
}).done(function (data) {
alert(data);
});
Add ApplicationService as a base for your MyTaskAppService class.
See my code;
public class MyTaskAppService : ApplicationService, IMyTaskAppService
{
private readonly IMyTaskRepository _mytaskRepository;
public MyTaskAppService(IMyTaskRepository mytaskRepository)
{
_mytaskRepository = mytaskRepository;
}
Task<List<string>> IMyTaskAppService.GetMyTasks(int input)
{
return _mytaskRepository.GetMyTasks(input);
}
}
See TaskAppService.
public interface IMyTaskAppService : IApplicationService
{
Task<List<string>> GetMyTasks(int input);
}
See the complete source-code of SimpleTaskSystem
Related
I have made some code inside of the spring boot back-end application which allows me to change a property of a specific object, this property which needs to be changed is the "status" property:
#Entity
public class Pakketje {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int code;
private String status = "In magazijn";
public Pakketje() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
To change the property of that object, i will need to state the ID of that object (i think) inside of the react frontend application, and then fetch the PUT-method.
I will show you the method to change the property inside of my spring boot back-end application, this method can be found in the 'Service' class. 'bestaandPakketje' means existing pakketje.
#Override
public Pakketje getPakketjeById(int id) {
return pakketjeRepository.findById(id).orElse(null);
}
#Override
public Pakketje statusOnderweg(Pakketje pakketje) {
Pakketje bestaandPakketje = pakketjeRepository.findById(pakketje.getId()).orElse(null);
bestaandPakketje.setStatus(pakketje.getStatus());
return pakketjeRepository.save(bestaandPakketje);
}
}
And here is the controller:
public class PakketjeController {
#SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
#Autowired
private PakketjeService pakketjeService;
#PostMapping("/add")
public String add(#RequestBody Pakketje pakketje) {
pakketjeService.pakketjeOpslaan(pakketje);
return "Pakketje opgeslagen!";
}
#GetMapping("/getAll")
public List<Pakketje> getAllePakketjes(){
return pakketjeService.getAllePakketjes();
}
#GetMapping("/getById/{id}")
public Pakketje findPakketjeById(int id) {
return pakketjeService.getPakketjeById(id);
}
#PutMapping("/updateOnderweg")
public Pakketje statusIsOnderweg(#RequestBody Pakketje pakketje) {
return pakketjeService.statusOnderweg(pakketje);
}
}
Now the next step is verry hard for me. Each 'pakketje' has his own button which can be clicked to change the property (I will upload the picture so please check it). When that button is clicked the property automatically should change from "In magazijn "to "onderweg".
I would appreciate some help!
Goal
To protect the web app from malicious spam bot crawlers and similar malicious actors my goal is to use reCAPTCHA v3 to analyze the user visiting the site and if the Captcha v3 score is good enough (let's say 0.5 or better) use the Fetch API to POST the token and so verify it and if the score is good enough as mentioned previously return the E-Mail address within some HTML. For simplicity sake, the function loadContactbubble() gets executed when you click a button.
Problems
I am not sure where to implement the if (response.score => 0.5) check.
Frontend semi-works in that regard that in the network browser debug tools it gives an response but in the console it prints out the response as undefined
Is my implementation secure enough? Can't the secret key somehow siphoned or similar?
I get a lot of CSP warnings in the browser, might this be an issue in production?
Code
I was following this guide: https://dev.to/spencer741/google-recaptcha-v3-server-side-validation-using-asp-net-core-5-0-3hfb (that means that the code is like 80-90% from this article)
My appsettings.json contains the secret key and the siteverify Link (API link).
GHttpModels.cs:
using System;
using System.Runtime.Serialization;
namespace _projectname.Tooling
{
public class GRequestModel
{
public string path { get; set; }
public string secret { get; set; }
public string response { get; set; }
public string remoteip { get; set; }
public GRequestModel(string res, string remip)
{
response = res;
remoteip = remip;
secret = Startup.Configuration["GoogleRecaptchaV3:Secret"];
path = Startup.Configuration["GoogleRecaptchaV3:ApiUrl"];
if (String.IsNullOrWhiteSpace(secret) || String.IsNullOrWhiteSpace(path))
{
//Invoke logger
throw new Exception("Invalid 'Secret' or 'Path' properties in appsettings.json. Parent: GoogleRecaptchaV3.");
}
}
}
//Google's response property naming is
//embarrassingly inconsistent, that's why we have to
//use DataContract and DataMember attributes,
//so we can bind the class from properties that have
//naming where a C# variable by that name would be
//against the language specifications... (i.e., '-').
[DataContract]
public class GResponseModel
{
[DataMember]
public bool success { get; set; }
[DataMember]
public string challenge_ts { get; set; }
[DataMember]
public string hostname { get; set; }
//Could create a child object for
//error-codes
[DataMember(Name = "error-codes")]
public string[] error_codes { get; set; }
}
}
GoogleReCaptchaV3Service.cs:
using System;
using System.Threading.Tasks;
using System.Text.Json;
using System.Web;
using System.Net.Http;
using System.IO;
using System.Text;
using System.Runtime.Serialization.Json;
namespace _projectname.Tooling
{
public class CaptchaRequestException : Exception
{
public CaptchaRequestException()
{
}
public CaptchaRequestException(string message)
: base(message)
{
}
public CaptchaRequestException(string message, Exception inner)
: base(message, inner)
{
}
}
public interface IGoogleRecaptchaV3Service
{
HttpClient _httpClient { get; set; }
GRequestModel Request { get; set; }
GResponseModel Response { get; set; }
void InitializeRequest(GRequestModel request);
Task<bool> Execute();
}
public class GoogleRecaptchaV3Service : IGoogleRecaptchaV3Service
{
public HttpClient _httpClient { get; set; }
public GRequestModel Request { get; set; }
public GResponseModel Response { get; set; }
public HttpRequestException HttpReqException { get; set; }
public Exception GeneralException { get; set; }
public GoogleRecaptchaV3Service(HttpClient httpClient)
{
_httpClient = httpClient;
}
public void InitializeRequest(GRequestModel request)
{
Request = request;
}
public async Task<bool> Execute()
{
// Notes on error handling:
// Google will pass back a 200 Status Ok response if no network or server errors occur.
// If there are errors in on the "business" level, they will be coded in an array;
// CaptchaRequestException is for these types of errors.
// CaptchaRequestException and multiple catches are used to help seperate the concerns of
// a) an HttpRequest 400+ status code
// b) an error at the "business" level
// c) an unpredicted error that can only be handled generically.
// It might be worthwhile to implement a "user error message" property in this class so the
// calling procedure can decide what, if anything besides a server error, to return to the
// client and any client handling from there on.
try
{
//Don't to forget to invoke any loggers in the logic below.
//formulate request
string builtURL = Request.path + '?' + HttpUtility.UrlPathEncode($"secret={Request.secret}&response={Request.response}&remoteip={Request.remoteip}");
StringContent content = new StringContent(builtURL);
Console.WriteLine($"Sent Request {builtURL}");
//send request, await.
HttpResponseMessage response = await _httpClient.PostAsync(builtURL, null);
response.EnsureSuccessStatusCode();
//read response
byte[] res = await response.Content.ReadAsByteArrayAsync();
string logres = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Retrieved Response: {logres}");
//Serialize into GReponse type
using (MemoryStream ms = new MemoryStream(res))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(GResponseModel));
Response = (GResponseModel)serializer.ReadObject(ms);
}
//check if business success
if (!Response.success)
{
throw new CaptchaRequestException();
}
//return bool.
return true; //response.IsSuccessStatusCode; <- don't need this. EnsureSuccessStatusCode is now in play.
}
catch (HttpRequestException hre)
{
//handle http error code.
HttpReqException = hre;
//invoke logger accordingly
//only returning bool. It is ultimately up to the calling procedure
//to decide what data it wants from the Service.
return false;
}
catch (CaptchaRequestException ex)
{
//Business-level error... values are accessible in error-codes array.
//this catch block mainly serves for logging purposes.
/* Here are the possible "business" level codes:
missing-input-secret The secret parameter is missing.
invalid-input-secret The secret parameter is invalid or malformed.
missing-input-response The response parameter is missing.
invalid-input-response The response parameter is invalid or malformed.
bad-request The request is invalid or malformed.
timeout-or-duplicate The response is no longer valid: either is too old or has been used previously.
*/
//invoke logger accordingly
//only returning bool. It is ultimately up to the calling procedure
//to decide what data it wants from the Service.
return false;
}
catch (Exception ex)
{
// Generic unpredictable error
GeneralException = ex;
// invoke logger accordingly
//only returning bool. It is ultimately up to the calling procedure
//to decide what data it wants from the Service.
return false;
}
}
}
}
Startup.cs:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
//from captchav3
using _projectname.Tooling;
namespace _projectname
{
public class CookieCheckMiddleware
{
private readonly RequestDelegate _next;
public CookieCheckMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Cookies["ModalShown"] == null && httpContext.Request.Path != "/Cookies")
{
httpContext.Response.Redirect("/Cookies?q="+ httpContext.Request.Path);
}
await _next(httpContext); // calling next middleware
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CookieCheckMiddlewareExtensions
{
public static IApplicationBuilder UseCookieCheckMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CookieCheckMiddleware>();
}
}
public class Startup
{
internal static IConfiguration Configuration { get; private set; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
//public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Captcha v3
services.AddHttpClient<IGoogleRecaptchaV3Service, GoogleRecaptchaV3Service>();
services.AddTransient<IGoogleRecaptchaV3Service, GoogleRecaptchaV3Service>();
services.AddControllers();
//Register dependencies
services.AddRazorPages();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//app.Use(async (ctx, next) =>
//{
// await next();
// if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
// {
// //Re-execute the request so the user gets the error page
// string originalPath = ctx.Request.Path.Value;
// ctx.Items["originalPath"] = originalPath;
// ctx.Request.Path = "/Cloud";
// await next();
// }
//});
// orig
//app.UseExceptionHandler("/Errors/{0}");
app.UseStatusCodePagesWithRedirects("/Errors/{0}");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// TEST
app.UseCookieCheckMiddleware();
app.UseAuthentication();
app.UseAuthorization();
var cookiePolicyOptions = new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.Strict,
};
app.UseCookiePolicy(cookiePolicyOptions);
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
// Experimental
endpoints.MapControllers();
});
}
}
}
_Layout.cshtml:
<button onclick="loadContactbubble();">Load contacts</button>
site.js (only the function for brevity):
function loadContactbubble() {
grecaptcha.execute('sitekeyhere', { action: 'onclick' }).then(function (token) {
console.log(token);
fetch("/load/contactbubble?RecaptchaToken=" + token, {
method: "POST",
body: token,
})
}).then((response) => {
console.log(response);
if (!response.ok) {
const errorBuild = {
type: "Error",
message: response.message || "Something went wrong",
data: response.data || "",
code: response.code || "",
};
}
}
//addText("Error: " + JSON.stringify(errorBuild));
//toggleLoader(2, "hidden");
//return;
)
}
ApiController.cs:
using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
using _projectname.Tooling;
using System.Threading.Tasks;
namespace _projectname.Controllers
{
public class SignUpModel
{
public string RecaptchaToken { get; set; }
}
[ApiController]
[Route("load/contactbubble")]
public class SignUp : ControllerBase
{
IGoogleRecaptchaV3Service _gService { get; set; }
public SignUp(IGoogleRecaptchaV3Service gService)
{
_gService = gService;
}
[HttpPost]
public async Task<IActionResult> Post([FromQuery] SignUpModel SignUpData)
{
GRequestModel rm = new GRequestModel(SignUpData.RecaptchaToken,
HttpContext.Connection.RemoteIpAddress.ToString());
_gService.InitializeRequest(rm);
if (!await _gService.Execute())
{
//return error codes string.
return Ok(_gService.Response.error_codes);
}
//call Business layer
//return result
return base.Content("<div>Welcome human! Here is our secret e-mail: test#test.com</div>", "text/html");
}
}
}
Errors
If I click the button the following gets printed out in the console:
Uncaught (in promise) TypeError: can't access property "ok", response is undefined
The response contains proper HTML in the network tab, which is weird.
How do I fix this?
Your function
function (token) {
console.log(token);
fetch("/load/contactbubble?RecaptchaToken=" + token, {
method: "POST",
body: token,
});
}
does not return anything, hence why the argument passed to the next .then((response) => ... is undefined.
Make this function return the fetched data, and it should hopefully work:
function (token) {
console.log(token);
return fetch("/load/contactbubble?RecaptchaToken=" + token, {
method: "POST",
body: token
});
}
(Well, it should then at least forward the fetch result to the next .then((response) => .... I have not looked for other errors in your code, so "it should hopefully work" is to be understood with respect to the one problem i explained here...)
In a class there are several static methods and the method to be called will be decided on the run time. How could I call this method dynamically?
export default class channel {
// METHOD THAT WILL DYNAMICALLY CALL OTHER STATIC METHODS
private static methodMap = {
'channel-create' : 'create',
'channel-user-count' : 'userCount',
'channel-close' : 'close'
};
public static do(commandType:string,params: any) {
if(channel.methodMap.hasOwnProperty(commandType)) {
// GET NAME OF THE METHOD
let method = channel.methodMap[commandType];
// CALL METHOD ON THE FLY
//return channel.call(method,params);
// channel.userCount(params);
}
}
/**
* Adds channel to available channel list
*/
private static create(channelName:string) {
}
/**
* Returns count of users in the channel
*/
private static userCount(channelName:string) {
}
}
You can dynamically invoke a method by using Classname['methodName'](param). As in your case, you can invoke create method as Channel['create']('MyChannel')
Here is the working example: Typescript Playground
class Channel {
private static methodMap = {
'channel-create' : 'create',
'channel-user-count' : 'userCount',
'channel-close' : 'close'
};
private static create(channelName:string) {
alert('Called with ' + channelName);
}
private static userCount(channelName:string) {
alert('Usercount called with ' + channelName);
}
public static do(commandType: string, params: any) {
if(Channel.methodMap.hasOwnProperty(commandType)) {
let method = Channel.methodMap[commandType];
return Channel[method](params);
}
}
}
Channel.do('channel-create', 'MyChannel');
Channel.do('channel-user-count', 1000);
Edit: Even though the above approach works, As #Ryan mentioned in his answer, providing functions directly in map is much cleaner.
private static methodMap: MethodMap = {
'channel-create': Channel.create,
'channel-user-count': Channel.userCount,
'channel-close': Channel.close,
};
Store the functions directly in the map:
type MethodMap = { [name: string]: (any) => void };
private static methodMap: MethodMap = {
'channel-create': Channel.create,
'channel-user-count': Channel.userCount,
'channel-close': Channel.close,
};
public static do(commandType: string, params: any) {
if (channel.methodMap.hasOwnProperty(commandType)) {
const method = channel.methodMap[commandType];
method(params);
}
}
To add to the answer by #HardikModha, you can also get the compiler to check the commandType against the possible values:
public static do(commandType: keyof typeof Channel.methodMap, params: any) {
if(Channel.methodMap.hasOwnProperty(commandType)) {
let method = Channel.methodMap[commandType];
return Channel[method](params);
}
}
...
Channel.do('channel-create', 'MyChannel'); // fine
Channel.do('channel-created', 'MyChannel'); // error
(code in playground)
I have a class-level Constraint on my class as below:
#NotEqualAccounts
public class FundTransferVO extends SignableVO implements Serializable{
private String fromAccount;
private String toAccount;
//setter,getter
}
and my custom Constraint code is:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = NotEqualAccountsValidator.class)
#ClientConstraint(resolvedBy=ClientNotEqualAccountsValidator.class)
public #interface NotEqualAccounts {
String message() default "{org.javaee7.validation.custom.constraint.NotEqualAccounts}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
I want to have a javaScript for client-side validation of my class using primeFace, I've already written the code below, but it doesn't work
PrimeFaces.validator['NotEqualAccounts'] = {
MESSAGE_ID: '...',
validate: function(element, fundTransferController) {
if(fundTransferController.fundTransferVO.getToAccount()===fundTransferController.fundTransferVO.getFromAccount()) {
msg = '';
throw msg;
}
}
};
fundTransferController is just my controller that my bean(fundTransferVO) is used in it.
Is there a way to validate class-level constraints on client-side using primeFace?
I just don't understand what I have to set as the service name for the EntityManager.
I hava two controllers: an ApiController and a 'normal' controller:
API Controller:
[BreezeController]
public class TournamentApiController : ApiController
{
private EFContextProvider<TournamentContext> _contextProvider;
public TournamentApiController()
{
_contextProvider = new EFContextProvider<TournamentContext>();
}
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[HttpGet]
public IQueryable<Tournament> Tournaments()
{
return _contextProvider.Context.Tournaments;
}
[HttpGet]
public IQueryable<Team> Teams()
{
return _contextProvider.Context.Teams;
}
}
'Normal' controller:
public class TournamentController : Controller
{
public ActionResult Index()
{
return PartialView();
}
public ActionResult Details()
{
return PartialView();
}
}
And in my DataSrvice.js file:
app.dataservice = (function (breeze) {
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
var serviceName = '/TournamentApi'; // What exactly do I need to set here?
// *** Cross origin service example ***
//var serviceName = 'http://todo.breezejs.com/breeze/todos'; // controller in different origin
var manager = new breeze.EntityManager(serviceName);
// manager.enableSaveQueuing(true);
var dataservice = {
getAllTournaments: getAllTournaments,
};
return dataservice;
/*** implementation details ***/
function getAllTournaments() {
var query = breeze.EntityQuery
.from("Tournament");
return manager.executeQuery(query);
}
})(breeze);
Can someone explain what is meant by a service name and thus, what I should use as the service name?
The serviceName identifies the service end-point, the route to the Web API controller. This will be the "root" of the URL you use to communicate with the server. So if the actual endpoints to query 'teams' and 'tournaments' are
http://foo/bar/tournamentApp/teams ...
http://foo/bar/tournamentApp/tournaments ...
then your service name will be
"foo/bar/tournamentApp"