In a pretty old .NET tutorial, "Nerd Dinner", it talks about using a Helper Class for Rule Violations. Everything seems straight forward except I'm not sure where to put this class so I can reference it. I am pretty new at MVC.
All of this below was taken from Nerd Dinner Tutorial:
Using a AddRuleViolations Helper Method
Our initial HTTP-POST Edit implementation used a foreach statement within its catch block to loop over the Dinner object's Rule Violations and add them to the controller's ModelState collection:
catch {
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(dinner);
}
We can make this code a little cleaner by adding a "ControllerHelpers" class to the NerdDinner project, and implement an "AddRuleViolations" extension method within it that adds a helper method to the ASP.NET MVC ModelStateDictionary class. This extension method can encapsulate the logic necessary to populate the ModelStateDictionary with a list of RuleViolation errors:
public static class ControllerHelpers {
public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable errors) {
foreach (RuleViolation issue in errors) {
modelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
}
}
Related
I'm needing to adjust some of the field attributes for the Location.VCashAccountID field on the Vendors screen - AP303000. When I put the code below into a customization DLL, it compiles fine and there are not apparent issues on the screen. However, when I try to publish the customization project with the DLL included, I get an error.
Code:
public class VendorMaintDefLocationExtExt : PXGraphExtension<VendorMaint.DefLocationExt,
VendorMaint>
{
public void _(Events.CacheAttached<PX.Objects.CR.Standalone.Location.vCashAccountID> e) { }
}
Error:
"Method Boolean DoValidateAddresses(PX.Objects.CR.Extensions.ValidateAddressesDelegate) in graph extension is marked as [PXOverride], but the original method with such name has not been found in PXGraph"
What am I missing?
TIA!
The following implementation will override the vCashAccount attribute on AP303000
public class AAVendorMaintDefLocationExtExtension : PXGraphExtension<DefLocationExt, DefContactAddressExt, VendorMaint>
{
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXUIField(DisplayName = "I am override")]
public void _(Events.CacheAttached<PX.Objects.CR.Standalone.Location.vCashAccountID> e) { }
}
You will also require the following references
using PX.Data;
using PX.Objects.AP;
using static PX.Objects.AP.VendorMaint;
The result can be seen in the snip below
The main difficulty in this task was the multitude of graph extensions utilized by the page. Though it's a beneficial design to encapsulate functionality it can be finnicky to determine which order they should be declared in a new extension.
You're graph extension extends VendorMaint.DefLocationExt which contains DoValidateAddresses. Try just extending VendorMaint.
I am using Guice's RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a background thread, using the same instances created during request.
However, when I call Provider.get(), guice returns an error:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
afaik, this is due to the fact that Guice uses thread local variables in order to keep track of the current request instances, so it is not possible to call Provider.get() from a thread different from the thread that is handling the request.
How can I get the same instances inside new threads using Provider? It is possible to achieve this writing a custom scope?
I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward #RequestScoped objects, only basic things like the HttpServletResponse. That's because #RequestScoped objects are not expected to be thread safe. You have some options:
If your entire #RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.
You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.
Some of my #RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, #ThreadSafeRequestScoped, and only forwarded those ones.
Code sample:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
#Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
#Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
#Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
#Override
public Boolean visitNoScoping() {
return false;
}
#Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
I have faced the exact same problem but solved it in a different way. I use jOOQ in my projects and I have implemented transactions using a request scope object and an HTTP filter.
But then I created a background task which is spawned by the server in the middle of the night. And the injection is not working because there is no request scope.
Well. The solutions is simple: create a request scope manually. Of course there is no HTTP request going on but that's not the point (mostly). It is the concept of the request scope. So I just need a request scope that exists alongside my background task.
Guice has an easy way to create a request scope: ServletScope.scopeRequest.
public class MyBackgroundTask extends Thread {
#Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
Oh, and you probably will need some injections. Be sure to use providers there, you want to delay it's creation until inside the created scope.
Better use ServletScopes.transferRequest(Callable) in Guice 4
I have been experimenting with the FXMLLoader and using the setControllerFactory method using a custom Callback<P,R> implementation.
The ORACLE documentation says the following:
An implementation might return a null value to indicate that it does
not or cannot create a controller of the given type; in this case, the
default controller construction mechanism will be employed by the
loader.
The result I want to achieve is that I can use a dependency injection framework to create any controllers that require parameters but I will let the FXMLLoader load any controllers that do not require parameters.
So if I have the following simple FXML file which uses the ViewController class which accepts no parameters...
<StackPane fx:id="pane"
xmlns:fx="http://javafx.com/fxml"
fx:controller="my.package.ViewController">
</StackPane>
and I use the following simple controller factory implementation to signal to the FXMLLoader that I want it to manage the construction of the controller in this case...
loader.setControllerFactory(new Callback<Class<?>, Object>(){
#Override
public Object Call(Class<?> type) {
return null; // Let the FXMLLoader handle construction...
}
});
after calling the load() method my Initialise method in the ViewController class is never called (I have verified this with a breakpoint).
If I change my controller factory implementation to return an instance of the ViewController class then everything works as expected.
Can anyone help me to clear up my confusion? Am I using the Callback interface incorrectly or is the ORACLE documentation incorrect?
javafx does the following in FXMLLoader:
try {
if (controllerFactory == null) {
setController(ReflectUtil.newInstance(type));
} else {
setController(controllerFactory.call(type));
}
} catch (InstantiationException exception) {
throw new LoadException(exception);
} catch (IllegalAccessException exception) {
throw new LoadException(exception);
}
so, yes, the oracle tutorial is incorrect.
Example: I would like to have a template that inserts a method. If the class is declared sealed, then I'd like the method to be declared private. If the class is not sealed, then I'd like the method to be declared protected virtual.
Another example. If the class is inherited, and the superclass contains a method X, then call base.X(); otherwise do nothing.
Is this type of conditional processing available in ReSharper? I guess this is getting close to T4 territory but it would be really handy to be able to do this in Live Templates.
In case it matters, I'm using R# 7.
Detailed scenario
Both of these requirements came from trying to write a Live Template for the IDisposable pattern (see Implementing the Disposable Pattern Correctly). The generated code needs to be different depending on whether the class is a base class or subclass. One can define two templates, but it is not difficult to dream up other scenarios where this would be useful. Here's the code in my IDisposable template:
#region IDisposable Pattern
/// <summary>
/// Finalizes this instance (called prior to garbage collection by the CLR)
/// </summary>
~$ClassName$() {
Dispose(fromUserCode: false);
}
public void Dispose()
{
Dispose(fromUserCode: true);
GC.SuppressFinalize(this);
}
private bool disposed = false;
// Declare as private if this class is sealed.
protected virtual void Dispose(bool fromUserCode)
{
if (!disposed)
{
if (fromUserCode)
{
// ToDo - Dispose managed resources (call Dispose() on any owned objects).
// Do not dispose of any objects that may be referenced elsewhere.
}
// ToDo - Release unmanaged resources here, if necessary.
}
disposed = true;
// ToDo: Call the base class's Dispose(Boolean) method, if available.
// base.Dispose(fromUserCode);
}
#endregion
You can certainly do this. What you need is a plugin that implements the corresponding live template macro that performs the actual check.
I am using the basic instructions (here) for creating a property driven by a custom ToolPart.
All is good, except for the part where, in order to access the webpart property within the ApplyChanges method I must cast the "this.ParentToolPane.SelectedWebPart" back to a concrete "SimpleWebPart" class.
public override void ApplyChanges()
{
SimpleWebPart wp1 = (SimpleWebPart)this.ParentToolPane.SelectedWebPart;
// Send the custom text to the Web Part.
wp1.Text = Page.Request.Form[inputname];
}
Doing this means that I must pair each toolpart with a specific webpart. Is there a better way?
I cannot create an interface as there is no way of specifying a property in one.
I ineptly tried an passing an event/eventhandler during toolpart creation, but that did not update the webpart property when called.
I could create a base class for all the webparts that have a public "Text" property, but that is fugly.
I could also get desperate and crack open the this.ParentToolPane.SelectedWebPart reference with Reflection and call any properties named "Text" that way.
Either way, I am staring down the barrel of a fair bit of faffing around only to find out each option is a dead end.
Has anyone done this and can recommend the correct method for creating a reusable toolpart?
I have used an interface instead of a specific instance of a webpart.
private class IMyProperty
{
void SetMyProperty(string value);
}
public override void ApplyChanges()
{
IMyProperty wp1 = (IMyProperty)this.ParentToolPane.SelectedWebPart;
// Send the custom text to the Web Part.
wp1.SetMyProperty(Page.Request.Form[inputname]);
}
But this does not give a compile time warning that the toolpart requires the parent webpart to implement the IMyProperty interface.
The simple solution to that is to add a property of the IMyProperty interface in the toolpart constructor and call this reference instead of the this.ParentToolPane.SelectedWebPart property.
public ToolPart1(IContentUrl webPart)
{
// Set default properties
this.Init += new EventHandler(ToolPart1_Init);
parentWebPart = webPart;
}
public override void ApplyChanges()
{
// Send the custom text to the Web Part.
parentWebPart.SetMyProperty(Page.Request.Form[inputname]);
}
public override ToolPart[] GetToolParts()
{
// This is the custom ToolPart.
toolparts[2] = new ToolPart1(this);
return toolparts;
}
This works fine, but I cannot get over the feeling that there is something nasty in the underlying SharePoint code that may trip me up later.