Context: Web application developed with ASPNet Core over ABP 2.9 framework (Razor pages).
I need to validate a model (it implements Validate(...) from IValidatableObject and calls the application service to perform some validations), then call an application service, and finally show a success message (with the same look & feel as abp.notify.success(...)).
Purpose of this post: To validate whether I am following the best practices or doing things in the correct way with ABP framework. If so, there are some suggestions to ABP team.
What I've tried:
1.- First, I tried submitting the form, but I didn't find an easy way to show the success message (like abp.notify.success ones) from the server method: public virtual async Task<IActionResult> OnPostAsync().
It would be nice to have a simple way to send client messages (like abp.notify.success ones) from server side. Maybe there is a way and I didn't find it.
2.- Second, I tried to cancel form submission and peform validation in client side, call the application service and show the message, also from client side. The issue here is that validations on public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) method were not executed from client side calling form.valid().
Possible improvement to ABP framework would be to enable an easy way to perform same server DataValidation() from client side. Maybe it exists and I didn't find it.
3.- Finally, I did the following:
a) Server side: to perform ValidateModel() and call the application service (see cshtml.cs code).
b) Client Side: avoid form submission and submit it with ajax, and finally show the success message with abp.notify.success(...)) (see javascript code).
Here are the questions related to previous issues. I appreaciate your comments or suggestions:
1.- Is there any better way to perform this scenario using ABP framework utils?
2.- Am I following the best practices? (placing the classes and logic in the correct layers)
DTO with data annotations in Application.Contracts layer.
DTOValidator class that inherits from DTO and IValidatableObject and implements Validate(...) method in Application.Contracts layer. This is to keep simple DTOs between client and application services.
Model class that inherits from DTOValidator and is binded to form in .cshtml.cs (Example: public class IndexPolicies : UpdatePolicyDtoValidator {})
You can cancel form submission and directly call application service. Then use DataAnnotations to validate your dto. If you need custom logic in validation, you can validate it in application service method (or create a custom DataAnnotation).
See https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC#dynamic-javascript-proxies for best way to call application service from javascript side.
Dealing with another issue I have found a solution that solves the problem taking full advantage of the ABP framework::
a) Server side: to perform ValidateModel() and call the application service (same as described on my third try).
b) Client Side: to use a simple button instead of submit one and call abpAjaxForm(options) with abp.notify.success() on success function. Then submit the form:
var _defaultPoliciesForm = $("#DefaultPoliciesForm");
var _saveButton = $("#SaveButton");
_saveButton.click(function (e) {
var options = {
beforeSubmit: function (arr, form) {
_saveButton.buttonBusy(true);
},
success: function (responseText, statusText, xhr, form) {
abp.notify.success(l("UpdatedSuccessfully"));
},
complete: function (jqXhr, status, form) {
_saveButton.buttonBusy(false);
}
}
_defaultPoliciesForm.abpAjaxForm(options);
_defaultPoliciesForm.submit();
});
Hope it can be useful to others with the same issue. Anyway, I remember my suggestions to ABP team:
Ability to send client messages like abp.notify.success(...) ones from server side.
Ability to perform same server validation as DataValidation() from client side
Related
I started to develp a new project with CQRS/ES. As I understand, one command raised a new event. So, I developped a web api with one action mapped to one command.
List of api action :
[Route("api/user/create"), HttpPost]
public Task<IActionResult> Handle(Commands.Create command)
=> HandleCommand(command);
[Route("api/user/update/name"), HttpPost]
public Task<IActionResult> Handle(Commands.UpdateName command)
=> HandleCommand(command);
In my IHM project developped with Blazor, how to communicate with the web api ?
Foreach change in a textbox, i send a http post ?
it's not really a best solution.
I prefer to add a submit button and send one http post. For this solution, how do I communicate all of user's action to web api ?
I would strongly suggest you to take a look at concepts like DDD. The first thing you have to do is get a clear understanding of your Domain.
Let's say that you're working on a Product Inventory system. In your Blazor app you might well have a "create product" page, containing a form with all the relevant fields (eg. "title", "description", "price" and so on).
The backend would expose a POST endpoint /products accepting a CreateProductDTO (check what a DTO is if you're unsure). The DTO would then be mapped into an immutable command, which will then get sent to the relative handler.
The idea is not to send every single user interaction to the server. You have to make a map of the possible actions exposed by your Domain and work your way up.
Thanks for your time , I have a simple question, in an asp.net MVC application, inside controllers is it possible that along with some methods returning View (ActionMethods) other could act as (or return) Json as a Web API (could be called from external apps).
Just trying to do a proper separations, hence trying to understand.
Thanks much.
You can make an action function like an API. Try something like the this.
// Controller/Action
[HttpGet]
public ActionResult IAmSpecial()
{
if (Request.IsAjaxRequest())
{
string[] objects = new string[] { "Foo", "Bar" };
return Json(objects);
}
return View();
}
This will return the IAmSpecial view if you browse to {domain}/{Controller}/IAmSpecial while it will return a JSON result if you use an AJAX Http Get request on the same url.
while it is possible to have controller methods which return Json data only, there are a number of considerations when you want to expose that data outside of the UI app.
Since you have an MVC app, I expect you have users and a way to login. Your controllers would more than likely be secured in some way, which works for the internal users of the application. Now you want to add one method which effectively becomes an API, available outside of the application and calls to it will have to be authenticated somehow.
What I would suggest is to split this up. You can create a separate project, which is a WebAPI one, in the same solution. The code which prepares the data can live in a class library you can then reference in both your MVC and WebAPI projects.
Your MVC app can call it and then return a view with that data, the WebAPI calls it and simply returns the data. You can now decide on a way of securing your API, maybe using Identity Server or some other way and you can keep adding things to it, without affecting the UI layer.
Your second option is to make the MVC app use the API when it needs to retrieve data, so both your public clients and UI use the same thing.
Whichever option you use, the idea is to not duplicate anything and at the same time provide the security layers you need.
I am developing a website along with an API to serve it data and have noticed that my current process involves repeated serialization and deserialization of the same data when an API call is made. I was wondering if there is a better way to go about things. Both the website and API are written in C# using ASP.Net Core 2.0.
My current process is as follows:
1) End user loads website page
2) AJAX call is made from client side JavaScript, calling a C# function in the website.
3) The C# website function calls the API (using a Swagger generated client).
4) The API serializes data and returns it to website as JSON.
5) The Swagger client in the web site deserializes the data back to a POCO class.
6) The Website C# function serializes the data back to JSON to return it to AJAX function.
7) Something is done with the JSON data in the client - inevitably after first parsing the JSON.
Example Code:
AJAX call:
var xhr = new XMLHttpRequest();
xhr.open('get', "/GetData", true);
xhr.onload = function () {
var data = JSON.parse(xhr.responseText);
doSomething(data);
}.bind(this);
xhr.send();
Website method:
[Route("/GetData")]
public async Task<IActionResult> GetData()
{
var data = await ApiClient.ApiDataGetAsync();
return Json(data);
}
API Method:
[HttpGet]
public Dictionary<int, string> GetData()
{
return _logic.GetData();
}
As the above shows the data is serialized to JSON by the API before being deserialized to a POCO by the Swagger client, then serialized back to JSON in the website to be processed client side.
I realize I could simplify this by calling the API directly from the AJAX rather than going through the website but I would rather avoid this for a number of reasons:
1) It would tightly couple the API to the front end of the website, at the moment I have the option of implementing an interface layer in the site to simplify things if the API needs to be replaced in the future.
2) It would reduce my control over who can access the API - at the moment it is locked down by IP address.
Is there a way I can improve this process so the data doesn't have to be serialized twice whilst retaining the Swagger client?
What problem are you actually trying to solve? The time taken to serialize/deserialize the json is tiny compared to the time taken for networked i/o.
At this point I would say you are trying to optimise something without knowing whether it will improve application performance or reduce cost, which is generally considered a waste of time.
Well, you can forgo the client and simply make your action a proxy using HttpClient to fetch from the API.
The client is intended to actually give you C# objects to work with, so it serializes/deserializes the request/response to make it easier for you to work with the API. That's sort of the whole point. What you're saying is that you don't actually want this, so simply drop the client.
Instead, you can make the request directly to your API from the action, using HttpClient, and then simply return the the response from the HttpClient call. Since the API returns JSON and you need JSON, no further processing needs to be done.
I have an UPDATE SQL transaction that connects to a SQL Server database using C# .NET 4.0 (I'm currently using SqlCommand.ExecuteNonQuery which is not Async so I'm sure I'm gonna need to change it). The transaction execution time is long (about a minute). I have ASP.NET application (Web Forms) and I wish to execute the transaction asynchronously while keeping the user able to interact with the application (navigating through pages). After the execution is finished, I wish to push kind of a notification to the user telling him that the transaction is finished.
I realize that my problem has two parts: the ADO.NET Async part and the part of triggering the application to push a notification to the client when the transaction is complete.
What's the best approach to implement both parts?
SignalR will fulfill your requirement
http://www.codeproject.com/Articles/315938/Real-time-Asynchronous-Web-Pages-using-jTable-Sign
or after SQl operation you can get response from Executenonquery and save it into hidden field, in client side you can use Jquery setInterval to check th hidden field value
Actually You can use jquery to do asynchronous call to the method that execute SQL transactions then you will return a message to the user after code execution has been finished.
For more information check the following example
Jquery Code
$.post( "PageName.aspx/UpdateMethodName", {}) //you can replace method name
.done(function( data ) {
alert(data);
});
Now in your ASPX page you must have a static method decorated with [WebMethod] attribute
[WebMethod]
public static string UpdateMethodName() //method name will be called from jquery
{
// your
return "Message";
}
More Information can be found here
JQuery.Post()
Using jQuery to directly call ASP.NET AJAX page methods
I hope that help
How to do it? I am completely new to this and wish to start learning it. I am going to have a tree structure, most probably a html/Javascript tree which will need to be saved into the database through Web Services.
What is the most efficient way to do this with ASP .net web services + asp.net 3.5?
UPDATED:
thanks for all the answers, I am still missing some pieces to this scenario, namely:
1) when the node is to be added to the tree, a user will get a pop-up, where some info will be entered, saved in the database, and a integer code returned from the database. Upon it's return, I need do some logic, and insert a node(or several) into the node selected. And so on, so forth. SO from what i understand, this logic (the meat of the code) will have to be performed on the client, in my Javascript code.
2) What would trigger the tree "refresh" after the pop-up is closed?
3) Where is .net with this picture at all? From what I gather, no server-side coding is performed here at all (aside from Web Services).
Is that the general direction these days, step away from server-side coding with .net controls and use a Javascript lib of choice + web services?
Thanks everyone.
You can achieve this by using ASP.net Ajax calls. On the server-side you create a webservice (WCF or asmx) having the attribute ScriptService:
namespace MyCompany.Project.Services
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class MyWebServiceClass : System.Web.Services.WebService
{
[WebMethod]
public string GreetFromServer(string name)
{
return "Hello, " + name;
}
}
}
On the page, you add a ScriptManager referencing your webservice.
<asp:ScriptManager id="scriptManager" runat="server">
<Services>
<asp:ServiceReference Path="~/Services/MyWebServiceClass"/>
</Services>
</asp:ScriptManager>
Then on the client side (JavaScript):
function invokeService(){
MyCompany.Project.Services.MyWebServiceClass.GreetFromServer("Juri", onSuccess, onFailure);
}
function onSuccess(result){
//check if result different null etc..It will be in JSON format, so deserialize
//use result
}
function onFailure(){
//handle errors
}
That should just be a hint on how to create a service and access it from within JavaScript. I mostly wrote it out of my head now, without checking it.
A hint: use Firebug! It's really great for verifying the data that is sent back and forth between your JavaScript client code and the webservice on the server-side.
I've just written a blog post with a downloadable example that describes the communication of client-server using asmx as well as WCF webservices.
Encosia.com has everything you need:
Using jQuery to Consume ASP.NET JSON Web Services
I would suggest you use jquery on the client side in your html / Javascript tree. Here is a tutorial to get you started on using jquery with asp.net
http://dotnetslackers.com/articles/ajax/Using-jQuery-with-ASP-NET.aspx
Have a look
Consuming a Web Service using ASP.NET Ajax