Parameter attribute not showing up - c#

I'm working on an auditing piece and am trying to use an attribute to mark parameters to a method that should be recorded in the audit for additional information. However, for whatever reason, I can't seem to check for whether the attribute exists.
My code:
[Audit(AuditType.GetReport)]
public Stream GetReportStream([AuditParameter] Report report)
{
...
}
[AttributeUsage(AttributeTargets.Parameter)]
public class AuditParameterAttribute : Attribute
{
}
And, inside the interceptor where I'm trying to get it:
foreach (ParameterInfo param in invocation.Method.GetParameters ())
{
var atts = CustomAttributeData.GetCustomAttributes (param);
if (param.IsDefined (typeof(AuditParameterAttribute), false))
{
attributes.Add (param.Name, invocation.Arguments[param.Position].ToString ());
}
}
I started adding on some extra calls to try to get something to work; what's why the extra var atts is in there. The invocation variable has information about the method that's called, and I am able to get a ParameterInfo object representing the parameter out of it. But, no matter what I've tried, I never can get any custom attributes out of it.
What am I doing wrong here?

Got it. Turns out it was a problem with my inexperience with using Castle. I realized that it was going through a proxy based on the interface for the invoked class, which didn't have the attribute I was looking for. So, changing my code to this:
foreach (ParameterInfo param in invocation.MethodInvocationTarget.GetParameters ())
{
if (param.IsDefined (typeof(AuditParameterAttribute), false))
{
attributes.Add (param.Name, invocation.Arguments[param.Position].ToString ());
}
}
Using MethodInvocationTarget instead of Method fixed the problem.

Related

c# Reflection change get method of a property

In my C# project I have a dependency on a 3rd party library. Now I want to write an automated acceptance test for my project. However to invoke the test I need an instance of a class from the 3rd party library. Using reflection I managed to set the values as I needed them apart from one.
Here is the relevant class that I am having the issue with:
public class SystemResults
{
// There must be something like this. However I cannot see it as it is private.
private List<Positions> xyz = new List<Positions>();
public IList<Positions> Positions
{
get
{
return xyz;
}
// This property does not have a set method
}
}
Here is what I have tried so far:
private void InitSystemResults(Type trueSysResType, SystemResults sysRes)
{
List<Position> positions = ImporterTools.GetPositions(PositionsCsv);
trueSysResType.GetProperty("Positions").SetValue(sysRes, positions); // ==> Here I get an exception
}
When I invoke the SetValue() method the following exception is thrown.
System.ArgumentException : Property set method not found.
From this information I figured out, that the class must look as I described above.
Now I would like to proceed with this some how. Has anybody an idea how I can achieve that when I access sysRes.Positions my positions are returned by the get method? Or is there a way to change the get method?
You can use BindingFlags.NonPublic,
FieldInfo[] fields = typeof(SystemResults).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).ToArray(); // gets xyz and the other private fields
List<int> testResults = new List<int>() { 1,23,4,5,6,7}; // list of integer to set
SystemResults sysres = new SystemResults(); // instance of object
fields[0].SetValue(sysres, testResults); // I know that fields[0] is xyz (you need to find it first),
// sets list of int to object
Hope helps,
{get;} only properties can have a backing field but Positions may be returning something completely different (not a value of a backing field, but maybe a result of a function).
Your code could accept ISystemResults which you can mock and in real code you could have a class SystemResultsFacade which internally calls the 3rd party code.

Optional in FormDialog

I'm using MS bot framework and FormDialog to ask the user to fill a form.
I would like some of the parameters to be optional and therefore added [Optional] indication to them:
[Prompt("Please specify if you have any additional requirements")]
[Optional]
string AdditionalRequirement { get; set; }
However, these questions still appear when the bot is filling up the form, and there is no way for the user to skip them (for instance just type "enter" or "skip")
Is there anything I'm doing wrong or is this the expected behavior? Is it possible to have a parameter that the user can skip in case it is not necessary?
update: seems the expected behaviour is that the optional parameters always show and there are certain words that can be understood as skipping the question, such as "No preference".
An answer that would explain how to add "skip" as one of the words to skip the question would be accepted.
I can think on two possible ways of achieving this (I couldn't test them, sorry!)
1) Decorate the optional field with a Template attribute, specifying the TemplateUsage.NoPreference usage as this.
[Template(TemplateUsage.NoPreference, "skip")]
2) Add the Skip term to the NoPreference array of the FormBuilder<T> configuration. Something like:
public static IFormBuilder<T> CreateCustomForm<T>()
where T : class
{
var form = new FormBuilder<T>();
var noPreferenceTerms = form.Configuration.NoPreference.ToList();
noPreferenceTerms.Add("skip");
form.Configuration.NoPreference = noPreferenceTerms.ToArray();
return form;
}
That then you can use like:
return CreateCustomForm<MyForm>()
As far as I know there isn't a way to add a Optional annotation to a field. What I know you can do is to pass a delegate to a method (or an anonymous method) where you can perform a check to see if the current field is active or not. If not, the field will not be prompted to the user. Heres a brief example:
public static IForm<MyForm> BuildForm()
{
return new FormBuilder<MyForm>()
.Field(nameof(AdditionalRequirement), active: IsAdditionalRequirementActive)
.Build();
}
private static bool IsAdditionalRequirementActive(MyForm state)
{
if (state.SomeOtherField == "Value")
return true;
else
return false;
}

The following throws 'is a Method but treated like a type'

The most confusing error I have ever seen in ASP. I have done method calls like this before, and have no issue in other spots of my code.
First of all the class:
namespace LocApp.Helpers.Classes.LocationHelper
{
public class QueryHelper
{
private LocAppContext db = new LocAppContext();
public static IEnumerable<Service> getAllService()
{
using (var db = new LocAppContext())
{
var service = db.Locations.Include(s => s.LocationAssignment);
var serv = (from s in db.Services
where s.active == true
select s).ToList();
return serv;
}
}
}
}
Pretty easy to understand whats going on. So lets call the method:
IEnumerable<LocApp.Models.Service> Service = new LocApp.Helpers.Classes.LocationHelper.QueryHelper.getAllService(Model.id);
getAllServices(Model.id) is throwing the error "is a method but treated like a type" , um no its not be treated like a type....
whats going on?
Well it's exactly as the error message says. getAllService() is a method:
public static IEnumerable<Service> getAllService()
But you're trying to use it as if it were a type with a constructor:
Service = new LocApp.Helpers.Classes.LocationHelper.QueryHelper.getAllService(...)
The new part is the mistake here. You don't want to call a constructor, you just want to call a method. It's a static method, so you don't need an instance - you can just use:
Service = LocApp.Helpers.Classes.LocationHelper.QueryHelper.getAllService(...)
Note that if you have appropriate using directives, follow .NET naming conventions and take care about singular/plural names, your code will be easier to follow:
var services = QueryHelper.GetAllServices(...);
Do you not simply mean:
IEnumerable<LocApp.Models.Service> Service = LocApp.Helpers.Classes.LocationHelper.QueryHelper.getAllService();
Get rid of the new bit, essentially, and that method doesn't take any parameters either - I'd assume you'd run into that problem after you removed the new bit.
Your getAllService method doesn't take any arguments, so you should call it without. Also it is a static method so don't use the new keyword:
IEnumerable<LocApp.Models.Service> Service = LocApp.Helpers.Classes.LocationHelper.QueryHelper.getAllService();

Error with xml serialization in c# - paramaterless constructor

I am trying to serialse a fingerprint FMD to XML using the code below, but get an error:
Error: DPUruNet.DataResult`1[DPUruNet.Fmd] cannot be serialized
because it does not have a parameterless constructor.
public void storePrint(DataResult<Fmd> resultConversion)
{
//store fingerprint as byte and insert to server------------
using (StreamWriter myWriter = new StreamWriter("test.txt", false))
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(resultConversion.GetType());
x.Serialize(myWriter, resultConversion);
}
MessageBox.Show("Fingerprint Stored!");
//------------------------------------------------------------
}
private void OnCaptured(CaptureResult captureResult)
{
try
{
// Check capture quality and throw an error if bad.
if (!_sender.CheckCaptureResult(captureResult)) return;
count++;
DataResult<Fmd> resultConversion = FeatureExtraction.CreateFmdFromFid(captureResult.Data, Constants.Formats.Fmd.ANSI);
SendMessage(Action.SendMessage, "A finger was captured. \r\nCount: " + (count));
if (resultConversion.ResultCode != Constants.ResultCode.DP_SUCCESS)
{
_sender.Reset = true;
throw new Exception(resultConversion.ResultCode.ToString());
}
preenrollmentFmds.Add(resultConversion.Data);
//--------------------CALL METHOD
storePrint(resultConversion);
//
The class DataResult is being referenced, so I can not alter it
UPDATE
If you don't have access to the DataResult<T> class, then you might have to take a slightly different approach and wrap this class with a different, serializable one. You can find a full example here:
How can I XML Serialize a Sealed Class with No Parameterless Constructor?
Previous Answer
The error is clear; you just need to add a parameterless constructor to the DataResult<T> class:
public class DataResult<T>
{
// Add a default constructor (public visibility, no parameters)
public DataResult()
{
// You can still define a method body if you wish,
// no restrictions there. Just don't do anything that
// could jeopardize the (de)serialization.
}
}
As for the implications of adding a default constructor, without knowing what
FeatureExtraction.CreateFmdFromFid(...)
is doing to create the DataResult<Fmd>, it would be impossible to know whether it would cause any issues.
Thanks to Cory, that is a useful answer, however in this example there is another way of serializing using
tempFingerPrint = Fmd.SerializeXml(resultConversion.Data);
this is specific to the Digital Persona SDK

Optional parameters with a stub in RhinoMock

I want to stub a function that receive 2 boolean parameters. The first is required and the second is optional. If I try to send Arg.Is.Anything to the first but without information for the second, I receive an error:
System.InvalidOperationException : When using Arg, all arguments must be defined using Arg.Is, Arg.Text, Arg.List, Arg.Ref or Arg.Out. 2 arguments expected, 1 have been defined.
Here is a sample of my class to stub:
public interface IOptionalParameterTester
{
bool IsValid(bool mustCheck, bool checkInDatabase = true);
}
public class OptionalParameterTester : IOptionalParameterTester
{
public bool IsValid(bool mustCheck, bool checkInDatabase = true)
{
if (checkInDatabase)
return true;
else
return false;
}
}
And here is a sample of the test:
[Test]
public void ValidateProducerTest()
{
IOptionalParameterTester optionalParameter = MockRepository.GenerateStub<IOptionalParameterTester>();
optionalParameter.Stub(x => x.IsValid(Arg<bool>.Is.Anything)).Return(true);
}
In this case, if I want the test to pass without error, I must define the same information that for the first (Arg.Is.Anything) or a specific boolean value like true or false.
If I set anything other than Arg.Is.Anything for the first parameter, I don't have any error.
Is it a bug?
Can I setup an option in RhinoMock to don't have to define a value for each optional parameter?
If there is no setup, is there a better thing to do to handle this case (Best practice, pattern, etc.)?
Thank you.
I think I understand what you are trying to do but, since it seems that this is a limitation of Rhino Mocks (we can get to that conclusion from the error message you are receiving) I would suggest to change your testing strategy.
Try doing the following:
[Test]
public void ValidateProducerTest()
{
bool anyBooleanValue = true;
IOptionalParameterTester optionalParameter = MockRepository.GenerateStub<IOptionalParameterTester>();
optionalParameter.Stub(x => x.IsValid(anyBooleanValue)).Return(true);
}
I know that on your test you want Rhino Mocks to ignore the first parameter and that it takes the optional second one but, depending on the logic you want to test, just hard code the first parameter and Rhino Mocks should not complain.
As long as on your test it is clearly stated that the first parameter's value is not relevant your test is valid and readable.
Just had a similar issue myself, try
optionalParameter.Stub(x => x.IsValid()).IgnoreArguments().Return(true);
This is quite an old question now, but I landed on this page because I was having issues with AssertWasCalled and optional parameters.
Eventually, I solved my problem using the following syntax found on this page: http://petermorlion.blogspot.com/2012/11/rhinomock-assertwascalled-vs.html.
string expectedMessage = "RhinoMocks baby!";
string actualMessage = "RhinoMocks dude!";
var fooMock = MockRepository.GenerateMock<ifoo>();
fooMock.Bar(actualMessage);
var calls = fooMock.GetArgumentsForCallsMadeOn(x => x.Bar(string.Empty), o => o.IgnoreArguments());
Assert.AreEqual(1, calls.Count);
var arguments = calls[0];
Assert.AreEqual(expectedMessage, arguments[0]);

Categories