Automapper isn't using extension methods for mapping - automapper

I have automapper setup like this
services.AddAutoMapper(typeof(MappingAssembly).Assembly, typeof(AssemblyWithExtensionMethods).Assembly);
And in one of my profiles
public class UserModuleMapper : Profile {
public UserModuleMapper() {
IncludeSourceExtensionMethods(typeof(UserGroup));
CreateMap<UserGroup, UserGroupDto>(MemberList.Destination);
}
}
And I have defined the extension method as
public static List<string> GetRoleNames(this UserGroup group) {
return group.UserGroupRoles.Select(x => x.Role.Name).ToList();
}
I have a property on DTO defined as
public List<string> RoleNames { get; set; }
As per the automapper documentation, I have made the following assumptions:
IncludeSourceExtensionMethods, which include extension methods while mapping
while mapping it will also look for methods with prefix Get
But when I validate the automapper extension I get error for unmapped property
Unmapped properties: RoleNames
What is missing in my configuration, automapper should detect the extension method.
I have tried (a) remove GET from the method name, but still does not work (b) moving CreateMap before or after the IncludeSourceExtensionMethods to see if sequence matters, but none of it helped.

With in few minutes after posting the question I got the answer by carefully looking at this issue on Github
The issue was with below statement
IncludeSourceExtensionMethods(typeof(UserGroup));
the type mentioned here should be of extension class
IncludeSourceExtensionMethods(typeof(UserGroupExtensions));
Not deleting the question, as it might help someone in future.

Related

How do I correct PX1011 warning from Acuminator? (it suggests sealing class, but that causes errors in error list)

I needed to add a new field to SOOrder and update attributes of another field. Both classes inherit PXCacheExtension, and both give a PX1011 warning that
Because multiple levels of inheritance are not supported for PXCacheExtension, the derived type can be marked as sealed. I had extended it originally from within Acumatica 2018R1 but have moved the code from within the customization project into my Visual Studio Extension Library.
I started with:
public class SOOrderExt : PXCacheExtension<PX.Objects.SO.SOOrder>
If I change the declaration of the class to be:
public sealed class SOOrderExt : PXCacheExtension<PX.Objects.SO.SOOrder>
I get CS0549 SOOrderExt.UsrMyField is a new virtual member in a sealed class 'SOOrderExt'.
Thinking that maybe I missed something and don't need to declare my virtual int?, I commented out:
public virtual int? UsrMyField { get; set; }
and got CS1061 'SOOrderExt' does not contain a definitionfor 'UsrMyField' and no accessible extension method 'UsrMyField; accepting a first argument of type 'SOOrderExt' could be found.
Is the original PX1011 warning something I should ignore, or is there something special needed to follow the guidance to make it sealed or to know that sealing the class is not appropriate?
In short, how do I make these Acuminator warnings go away without simply suppressing and still define my fields?
I'm on 2018R2 Build 18.212.0033 with Visual Studio 2019 Community Edition and Acuminator 1.6.1.
You need to declare the property but the virtual keyword doesn't seem necessary. Otherwise the warning is an oversight if sealed = no virtual and no virtual = no custom fields.
Without virtual keyword this cache extension seems to be working fine:
public sealed class SOLineExt : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region UsrField
[PXDBString(12)]
[PXUIField(DisplayName="Field")]
// Ommit declaring the type as virtual
public /*virtual*/ string UsrField { get; set; }
public abstract class usrField : PX.Data.BQL.BqlString.Field<usrField> { }
#endregion
}

How to access Obsolete variables in graph extension

I have field declared with obsolete in some other project, how i can access this field in my extended graph.
[Obsolete("Use AMShiftMst.shiftType", true)]
public abstract class shftDiff : IBqlField, IBqlOperand
{
protected shftDiff();
}
You cannot use this class shftDiff because the ObsoleteAttribute marks any usage as an error. The message in the obsolete call mentions the new object to use.
See ObsoleteAttribute(String, Boolean) here:
ObsoleteAttribute Class
However related to the product it looks like the message should indicate to use AMShiftMst.shftDiff and not AMShiftMst.shiftType as shiftType doesn't exist.
Using AMShiftMSt.shftDiff should solve your issue.

How do you get ServiceStack.ToJson to *sometimes* ignore properties?

I have a ServiceStack DTO:
[Route("/images", "POST")]
public class PostImageCommand
{
public string Notes { get; set; }
public byte[] Image { get; set; }
//other properties removed for brevity
}
I also have a part in my code that logs messages using log4net. I do this by serializing the command. For example, I just do this:
var command = new PostImageCommand(){
//set properties
};
var commandJson = command.ToJson();
MyLogClass.Log(commandJson);
The problem: The Image byte array can get pretty large. I do not want to serialize this property when logging, or else my log will be filled with large amounts of image data.
I tried putting the [IgnoreDataMember] attribute on the Image byte[] in the DTO. However, that causes the build to fail without Visual Studio saying why. I can put the Attribute on the Image property, but when I try to build I see this:
No reason why the build failed, just these messages. The Output tab only says "The operation was canceled".
My question: What is the easiest way to ignore a DTO property from being serialized in my situation?
This previous answer lists the different ways to ignore properties in ServiceStack.Text. But really if you just want to ignore the property from being logged you can just set the property to null then restore it, map it to a different model with just the types you want serialized using the built-in AutoMapping tools, Use ToObjectDictionary() extension method to serialize your model into a dictionary then remove the items you don't want logged.
The issue you're having with the [IgnoreDataMember] attribute is because you haven't referenced the System.Runtime.Serialization .NET Framework Assembly.

How to inject properties when using Castle Windsor

I am new to IOC.
I've MethodProfilerAspectAttribute attribute which has to be applied on any method like this
[MethodProfilerAspectAttribute(5)]
public void MethodName(){}
Here is the implementation of MethodProfilerAspectAttribute
[Serializable]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class MethodProfilerAspectAttribute : OnMethodBoundaryAspect
{
public ILogger logger { get; set; }
public int x{get;set;}
public MethodProfilerAspectAttribute(int x)
{
this.x=x;
}
public override void OnSuccess(MethodExecutionArgs args)
{
logger.CustomLogging("logMe");
base.OnSuccess(args);
}
}
I want to resolve my ILogger dependency using Log4NetLogger which is registered and resolving constructor dependencies properly by using following :
container.Register(Component.For<ILogger>().ImplementedBy(typeof(Log4NetLogger)));
but unfortunately whatever I've tried for resolving property dependency, is not working.
Any help would be greatly appreciated.
The link you provided just describes property injection for components resolved from the container. Attributes are not resolved from the container, but instead are created by the CLR. You might be able to jigger a way to set attribute properties by providing a custom IContributeComponentModelConstruction implementation, but I'm not so sure. See answers for similar questions here, here, and here (from the creator of Windsor).
In any case, attributes is not where you want to put functionality. They should be minimal, just providing metadata. I see here you're trying to provide some sort of functionality across all method invocations. You may want to consider Windsor's interceptors to provide similar behavior.

Mule Issue : More than one JAXBContext

We are facing one issue in our Mule Adapter related to JAXB context, needed some opinion on the same
We are using xpath to evaluate some expressions in the choice blocks in our adapter like below for instance,
<choice doc:name="Choice">
<when expression="//env:abc/env:Body/ref:dataelement/ref:/ref:element" evaluator="xpath">
......
</when>
Now, this works perfectly fine in our application but the problem arises when one of other team uses this Adapter as a jar in their application.
When they try to use this adapter, they are getting below error,
Message : More than one object of type class javax.xml.bind.JAXBContext registered but only one expected.
Type : org.mule.api.registry.RegistrationException
Code : MULE_ERROR--2
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/registry /RegistrationException.html.
After debugging with the help of loggers etc, we narrowed down to the choice block used above which is causing this particular issue. Also, googled a bit and found one of the posts pointing out the same issue.
Also, to confirm we commented out the choice block having xpath expression and the flow went ahead but broke again where was xpath used in some other way.
https://www.mulesoft.org/jira/browse/MULE-5926
Can anyone please suggest any suitable workaround to resolve this issue?
I agree with you. It is an unresolved issue in Mule.
One solution we have implemented is not define the jaxb context in the config you are providing in the jar file.
Along with the jar file, give instructions to the end application using it, to include the JAXB packages in their JAXB Context object definition.
This way there will be only one JAXB context and it will work smoothly.
Hope this helps.
This is a bit late however the solution that worked was
<mulexml:jaxb-context name=“JAXB_Context“ packageNames=“org.example.test1:org.example.test2“ doc:name=“JAXB Context1“ />
Please note that there must be no space between package names.
Thanks to: http://dominikbial.de/quicktipp-working-with-more-than-one-package-name-in-a-jaxb-context-config-in-mule-esb/
As of now we cannot add more than one JAXBContext in mule. As an alternative you can write your custom transformer.
I implemented something like
public interface MyAppJaxbObj2XmlComponent<I,O> extends
MyAppComponent<I,O>,Callable {
public O marshal(I input) throws Exception;
}
Abstart transformer
public abstract class AbstractMyAppJaxbObj2XmlComponent<I,O> implements
MyAppJaxbObj2XmlComponent<I,O>{
private Class<I> inputType;
public AbstractMyAppJaxbObj2XmlComponent(){
this.inputType = (Class<I>) new TypeToken<I>(getClass())
{}.getRawType();
}
public AbstractMyAppJaxbObj2XmlComponent(Class<I> type){
this.inputType = type;
}
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
I input = eventContext.getMessage().getPayload(inputType);
O output = marshal(input);
return output;
}
}
Your flow transformer this will load your needed jaxb during startup.
#Component
public class MyFlowJaxbObj2XmlComponent extends
AbstractMyAppJaxbObj2XmlComponent<RequestPayloadType,String> {
#PostConstruct
public void init() {
//Load your schema during startup
}
}
You can also implement a fluid interface as an alternative for this.

Resources