In my Grails app, I am using methods in a service to do complicated validation for user submitted data. Unfortunately, Grails is quietly sabotaging me.
I populate the domain instance with the user submitted data
I hand the instance off to the service, which analyzes the properties.
If errors are found I add them using
instance.errors.rejectValue('myValue','errors.customErrorCode','Error')
BEHIND THE SCENES, when the service passes the domain instance back to the controller grails checks for changed properties and calls validate() before returning the instance. (verifiable by seeing the beforeValidate event called on returning a domain instance from a service to a controller where one or more properties has changed)
That behavior clears any custom errors I have added and the instance I get back in the controller is now incorrectly without error.
How can I
A) stop grails from validating between service and controller
OR
B) prevent a validate() call from wiping my custom errors.
EDIT
So far I've found one partial answer,
If you use instance.get(params.id), grails will self validate behind the scenes wiping custom errors.
If you use instance.read(params.id) you can bypass this behavior to an extent.docs
But this solution is limited by domain relationships. Any other solutions welcome.
Seems that it is not custom validation. It can be because of transactional service. Service opens separate transaction for each method and clears entities after method end. You can find this mentioned in docs(read the last paragraph of part ). So errors dessappear not because of validation.
Don't know if your service is transactional. But if it is - you can add #NotTransactional annotation to method were you want not to loose errors. And
errors will be saved.
Hope it helped,
Matvei.
Not sure how your code looks like or what is causing the problem, but in any case I strongly suggest implementing custom validators in the domain class or in a command object within the constrains.
Here are some examples from grails docs:
http://docs.grails.org/2.4.0/ref/Constraints/validator.html
Related
I recently downloaded a Single Page Web Application (Angular) from https://aspnetboilerplate.com/Templates using 3.x target version.
I just simply added a few entities and then started to follow the steps on this page https://aspnetboilerplate.com/Pages/Documents/Application-Services
Things do work well for me to Get, List, Update, and Delete entities when my app service class is just inheriting AsyncCrudAppService<Entities.PhoneBook, PhoneBookDto, long, GetAllPhoneBooksInput>, however when it is inheriting AsyncCrudAppService<Entities.PhoneBook, PhoneBookDto, long, GetAllPhoneBooksInput, CreatePhoneBookInput, and UpdatePhoneBookInput> the swagger definition will no longer load.
GitHub Repo: https://github.com/woodman231/MyPhoneBooks
(which currently does not work and will not load Swagger page).
I can get the swagger page to load by removing CreatePhoneBookInput and UpdatePhoneBookInput from
https://github.com/woodman231/MyPhoneBooks/blob/main/aspnet-core/src/MyPhoneBooks.Application/SimpleCrudAppServices/ISimplePhoneBookCrudAppService.cs#L9
and
https://github.com/woodman231/MyPhoneBooks/blob/main/aspnet-core/src/MyPhoneBooks.Application/SimpleCrudAppServices/SimplePhoneBookCrudAppService.cs#L14
However, again I am still unable to create entities using this default implementation. Any ideas?
I have cloned your repo and run it and I figured out the error, first as I tell you in comments I verified the text log, and it said the next:
System.InvalidOperationException: Can't use schemaId "$CreatePhoneBookInput" for type "$MyPhoneBooks.SimpleCrudAppServices.Dtos.CreatePhoneBookInput". The same schemaId is already used for type "$MyPhoneBooks.PhoneBooks.Dtos.CreatePhoneBookInput"
What happenig is that you have these two classes UpdatePhoneBookInput, CreatePhoneBookInput repeated in SanokeCrudAppServices\Dtos and PhoneBooks\Dtos
You have the classes in both folders with same exact name, and thats the problem, if you change the name in whatever place the swagger definition will load without errors, I have do it like this and everything works fine!
Change the name in one of the places, and all will be working fine
Personally I don't like to use a different Dto for Create and Update for me is easier to user just one Dto for all.
Ok I figured it out. I had also made a DIY AppService and some of the DTO Class Names associated with the DIY App Service clashed with the DTO Class Names associated with the Automated Service. It was acceptable in .NET since they were in different name spaces but once the swagger definition was configured I assume that there was multiple instances of the same DTO Defition. I checked the AbpLogs table but they didn't give me much details as to the specifics of the internal server error while loading the definition. It sure would have been useful to know that.
In the _Layout.cshtml, the #Html.MvcSiteMap().Menu("viewname") caused extra 2s in each request. I found that the repository's constructor being executed several times depends on the menu's count so I guess this might be where the extra 2 seconds cames from.
Is there a way to prevent the constructors be executed once the menu rendered?
I suspect the reason for this is because you are using Security Trimming. In order to determine whether each link has access, MVCSiteMapProvider creates and releases an instance of each controller for each action. The only way to avoid this is to disable security trimming.
With security trimming enabled, it is not recommended to have any heavy processing within your constructors, as this will negatively affect performance. You should defer any processing (such as opening database connections) to later on in the request lifecycle by using an Abstract Factory to create the connection and injecting the factory into your constructor instead of the dbcontext/connection object. See this post for an example.
That said, the AuthorizeAttributeAclModule is not as efficient as it could be because when you have controllers with a lot of action methods, the same controller instance could be reused instead of creating one for each action method. You could make a custom AuthorizeAttributeAclModule and use the HttpContext.Items dictionary to request-cache each controller so they are reused instead of re-instatiated. You will need to do some refactoring to do it, though. The controller is created on line 235 and it is released on line 108. You need to make sure that the release isn't called until the after very last node is checked. You can do this by creating an IActionFilter to release them after the action is complete, but it means that action method will need to know about the same request cache (in HttpContext.Items) as the AuthorizeAttributeAclModule. You just need to implement the OnActionExecuted method to clean up the controllers from the request cache.
I made a settings page for my website. On this page the user is presented with a bunch of site wide settings they can manipulate. I made it so when the user selects a setting the page will automatically run an ajax request to send the setting to the database. My question is in how I do this.
At first I just did calls to the repository. One call to get the data back, put it into a ViewModel then give that ViewModel to the View and the ajax controller just sent the settings back to the database. This way seemed like the best at first especially for unit testing purposes since I could just pass in a fake repository if needed. Then for the user to get a setting they just called the repository and pass in the setting name they want.
Then I had a bright idea. I made a singleton class called SiteWideSettings and each possible setting on the site was a property of the site. When SiteSettings is called for the first time all of the settings are loaded. When Set is called on any of the properties it will call the repository function to send the setting. Now with my Settings view I'm just passing in SiteWideViewOptions.Current and on the ajax call I'm updating the property that was changed. This is working for me however it's not very unit testable since I can't really pass in a repository to a singleton's constructor since its constructor is private. What I currently have is working fine but I just don't feel like it's the best solution and unit testing isn't really possible here.
I'm thinking of one of the following but not sure which is the best.
Add a Repository property to the SiteWideSettings class
Add a function to the SiteWideSettings class to pass in a repository
Not use a singleton for this at all and just go back to what I was doing before I had this idea
Any comment on this would be greatly appreciated.
Note: I know. I know I'm doing unit testing wrong in this case because I didn't write my test first so please don't scold me for that.. I have already scolded myself and with my next task I won't do it again I promise :)
"Then I had a bright idea. I made a singleton class called
SiteWideSettings and..."
This sounds like a bad idea. Let your database be ground-truth for what the settings are, not some in-memory cache that you now need to keep up to date. Let your ORM do caching if you need it for performance otherwise you are just adding problems especially if you now try to run your site on more than one server.
If you want to simplify the controller so it has less 'set-up' and 'tear-down' code in it, use an IOC (e.g. Autofac) and inject any dependencies you need (e.g. a DataContext or a Repository) on a per-http-request basis.
Your action methods are now easier to test since you can simply instantiate your controller (injecting the dependencies manually using its constructor) and then call your method.
Good day!
I used the Struts2 xml validation as instructed in this website.
The problem is when I clicked the submit button twice. The error message also appears twice...
My question is... how to clear the first error message before another action is processed to accommodate new set of error messages.
Thank you in advance.
If you are using the spring integration you have to define your bean as scope="prototype", then you get a new instance of your Action for every request.
The default scope for spring is singleton.
It's a good idea to do this for every Action.
Remove validate="true" from form tag.
There is a validator interceptor in the default stack. You just need to use that and using that is very simple. Just make a method in your action class by the name public void validate(). Within that validate() you can access the fields using their getters & then put the required validation onto them.
Also, with this implementation you would not have to worry about the multiple messages being shown, because it will show only the message what you set in the addFieldError method and removes any previously kept messages.
NOTE: Be sure to use getters of the variables in your validate(), because the variables in the action are not set at the time this interceptor is invoked.
Here is a link to a very nice tutorial.
http://www.vaannila.com/struts-2/struts-2-example/struts-2-validation-example-1.html
If you will keep validate=false, then validation xml will be called on submit action.
To clear messages on each submit click, if you are using table in your jsp then keep table outside of form. It will work.
NOTE: There are 3 questions in here and I did not make separate questions since they are all somewhat related to the same code.
I have the following code that registers the connection to my RavenDB in the Application_Start once per the application's life cycle:
var store = new DocumentStore { Url = "http://localhost:8080" };
store.Initialize();
builder.RegisterInstance(store).SingleInstance();
Now this works fine and this is something that should be created only once per the application's life cycle. Now I wanted to add in the DocumentSession to Autofac so I tried to add in this in the Application_Start:
var session = store.OpenSession();
builder.RegisterInstance(session).SingleInstance();
In my UserRepository I have the following constructor:
public UserRepository(DocumentStore store, DocumentSession session)
When I try to run this, I get the follow runtime error:
Cannot resolve parameter 'Raven.Client.Document.DocumentSession Session' of constructor 'Void .ctor(Raven.Client.Document.DocumentStore, Raven.Client.Document.DocumentSession)'
That error to me sounds like Autofac does not think it has a DocumentSession however that is what store.OpenSession() returns so it should. Anyone know what would be causing this error? Am I not setting the session variable correctly (it is the same as the store variable which works fine)?
Another thing which may or may not be related to the above issue is how do I add an instance of an object to Autofac per request instead of per the applications life cycle? While the RavenDB DocumentStore object should only be created once be the life application cycle, the DocumentSession should be created once per the request (maybe creating it per application level is causing the error above).
One last question I will throw there about Autofac (mildly related to the code above) is about releasing the objects. If you take a look at this tutorial:
http://codeofrob.com/archive/2010/09/29/ravendb-image-gallery-project-iii-the-application-lifecycle.aspx
The last piece of code:
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
and the point of this code is to prevent leaking the sessions. Now is this something I also need to worry about for Autofac and if so, how would I do this in Autofac?
I'm guessing you want something like:
builder.Register(c => c.Resolve<DocumentStore>().OpenSession()).InstancePerLifetimeScope();
"The default ASP.NET and WCF integrations are set up so that InstancePerLifetimeScope() will attach a component to the current web request or service method call." - Autofac: InstanceScope
Basically, in a web app, InstancePerLifetimeScope handles the one per HTTP context aspect, and also disposes any types that implement IDisposable.
There was also the issue that OpenSession returns a IDocumentSession instead of a DocumentSession. Changing my class to look for a IDocumentSession along with doing what Jim suggested worked, thanks.