I'm trying to extend System.Data.SqlClient.SqlException and add a property to it. So that, on every SqlCommand execution, if an exception is thrown, I can capture it, add the SQL that was executed, and re-throw it.
I have done extensions before, but only with methods. With properties I can't manage it to work.
public static class SqlExceptionExtention{
public static string query { get; set; }
}
I have tried all combinations of adding and removing the static flag, and nothing works. Of course the property can't be static, it must be specific to each object.
There's no such thing as extension properties, only extension methods.
If you want to add data then you could use the Data property to populate the dictionary:
try
{
// Do something
}
catch(SqlException e)
{
e.Data.Add("Foo", "Bar");
throw;
}
Related
Is there a way to do this:
var methodToDoStuffTo = typeof (FancyClass).GetMethod("MethodName").Name;
Without relaying on the string "MethodName"?
What I want is something like this:
var methodToDoStuffTo = typeof (FancyClass).GetMethod(FancyClass.MethodName).Name;
So I can be sure that there is no unexpected error when I rename my method MethodName.
For reasons I can't simple update my enviroment to c# 6, so no nameof().
I try and give a reason why I'am doing this:
I (have to) use one Authorization Attribute on several different Methods.
Depending on from which method the Attribute was 'called', the code has to do slitly different stuff.
That's why I can't / don't want to use differnet Attributes for each Method.
Depending on from which method the Attribute was 'called', the code has to do slitly different stuff
You should never do that. Letting magic stuff happen based on naming conventions is in most application code a bad idea that will lead to unexpected side-effects.
Just add a constructor parameter to the attribute:
public class YourAttribute : Attribute
{
private bool doSomethingDifferent;
public YourAttribute(bool doSomethingDifferent = false)
{
_doSomethingDifferent = doSomethingDifferent;
}
}
And apply it as such:
public class AttributeApplication
{
[YourAttribute]
public void NormalMethod()
{
}
[YourAttribute(doSomethingDifferent: true)]
public void MethodSomewhatDifferent()
{
}
}
But if you really want a type-safe GetMethod(), you could create an extension method with a MethodCallExpression, as explained in Get the name of a method using an expression.
The syntax will then become something like this:
var methodToDoStuffTo = typeof(FancyClass).GetMethod(c => c.MethodName()).Name;
But again, that approach should not be chosen lightly.
I'm currently working on some existing C# code and i simply want to set a property to null when a given code doesn't exist in the system.
The code i currently have looks like this:
if (!CodeExists(SomeClass.Code))
{
SomeClass.Code = null;
}
So assume that SomeClass.Code starts with a value of 100. It then checks if that Code exists with the method CodeExists(). If it can't find the code it should set SomeClass.Code = null.
But when i step through this piece of code with the debugger then i see that SomeClass.Code doesn't change at all, eventhough the debugger comes inside the if statement.
When i look at the property Code i see that it is declared as virtual:
public virtual CodeNumber Code { get; set; }
Does that mean i cannot simply change the value when it is declared as virtual? Is there anything i can do to change that value of Code?
Seems some other part of the code is the problem:
public SomeClassProjection SomeClass
{
get
{
// some stuff is done here
SomeClassState.Value = queryProcessor
.Execute(new ExistingProductsQuery { OrderNumber = SelectedOrderNumber });
return SomeClassState.Value;
}
}
So SomeClassState is returned. And that is defined like this:
public ViewValue<SomeClassProjection> SomeClassState;
So it does use another class like some of you suggested. And ViewValue clearly tells it is readyonly. That means i have to take another approach, but at least i now know what actually is prevents me from editting that property and that virtual has nothing to do with it.
About this topic:
So how do i accept an answer now that i found the solution? Or do i need to close this topic?
Seems some other part of the code is the problem:
public SomeClassProjection SomeClass
{
get
{
// some stuff is done here
SomeClassState.Value = queryProcessor
.Execute(new ExistingProductsQuery { OrderNumber = SelectedOrderNumber });
return SomeClassState.Value;
}
}
So SomeClassState is returned. And that is defined like this:
public ViewValue<SomeClassProjection> SomeClassState;
So it does use another class like some of you suggested. And ViewValue clearly tells it is readyonly. That means i have to take another approach, but at least i now know what actually is prevents me from editting that property and that virtual has nothing to do with it.
We have some setup classes in our project, which are serialized / deserialized with XmlSerializer from some .config-Files. In some of those setup classes we have collections of sub-setups like this:
using System;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
namespace Datev.Framework.Shared.Actions.Setup
{
[Serializable]
[XmlSerializerAssembly]
[XmlRoot("setup")]
public class SetupXml
{
public SetupXml()
{
SubSetups = new Collection<SubSetupXml>();
}
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public Collection<SubSetupXml> SubSetups { get; private set; }
}
[Serializable]
public class SubSetupXml
{
[XmlElement("someValue")]
public string SomeValue { get; set; }
}
}
We are using the attribute [XmlSerializerAssembly] to have the best performance for reading and writing the setups.
And here is my problem: We are using Collection to avoid the CA-Warning "Don't use arrays". When we make the setter of SubSetups public, we get the CA-Warning CA2227 "Don't make the setter of a collection public". If we make the setter of the property SubSetups private (like in the code sample), we'll get an error in the generated serializer. The method "GenerateSerializer" (invoked in a tool of us) the code has a line like this:
if (o.SubSetups == null) o.SubSetups = new Collection<SubSetupXml>();
If we make the setter private, we'll get a CS0200 "Property SubSetups cannont be assigned" during building the serializer.
Does anyone know how to make a correct setup with a generated serializer without suppressing a CA-Warning?
It is hard to tell: a "correct" setup depends highly on the context.
Just a quick idea: what happens if you move the logic from "GenerateSerializer" to the property getter? Would it be acceptable?
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public Collection<SubSetupXml> SubSetups {
get {
// subSetups needs to be a backing (private) field... is this a problem?
if (this.subSetups == null) this.subSetups = new Collection<SubSetupXml>();
}
private set;
}
This way, in "GenerateSerializer" you just get the collection. If the collection has not already been created, it will be inside the getter, without needing to create it outside the class.
Just an idea, let me know if it is not applicable.
If the situation is as straightforward as it seems then You don't need to check whether (o.SubSetups == null) because You have the line SubSetups = new Collection<SubSetupXml>(); in the SetupXml() constructor (that is, of course, if o is of type SetupXml). If you get rid of that if statement from the GenerateSerializer method and make the setter private You should be fine - there's no way the SubSetups property can be null unless there are some other ways of messing around with it that You didn't mention...
You could have something like this:
public class SetupXml
{
public SetupXml()
{
SubSetups = new Collection<SubSetupXml>();
}
[XmlIgnore]
public Collection<SubSetupXml> SubSetups { get; private set; }
[EditorBrowsable(EditorBrowsableState.Never)]
[GeneratedCodeAttribute("Whatever", "1.0.0.0")]
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public SubSetupXml[] SerializationSubSetups
{
get
{
return SubSetups.ToArray();
}
get
{
SubSetups = new SubSetups();
if (value != null)
{
foreach(SubSetupXml ssx in value)
{
SubSetups.Add(ssx);
}
}
}
}
}
It's not perfect, but the EditorBrowsable attribute will prevent developers using this library (from another assembly) to see it displayed by intellisense/autocompletion tools. And the GeneratedCode attribute will prevent CA warning on it.
I assume that you have already consulted this article?
http://msdn.microsoft.com/en-us/library/ms182327.aspx
This strikes me as an important note in that article:
"Both binary and XML serialization support read-only properties that are collections. The System.Xml.Serialization.XmlSerializer class has specific requirements for types that implement ICollection and System.Collections.IEnumerable in order to be serializable."
Further to that you may be able to make more progress with the .Clear() and then .AddRange() approach, detailed there.
You can try to implement IXmlSerializable interface. It requires a bit more work but it gives you fine control on the serialization, and in your case access to the private class variables. In ReadXml method you just have to create and instance of your collection, iterate over each node in the source xml and parse the value
Changing the type of SubSetups to IEnumerable will get rid of the code analysis warning, but I can't tell if this is appropriate for you.
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public IEnumerable<SubSetupXml> SubSetups { get; set; }
Basically, I would like to create a Method, that takes a base-class as a parameter, and can be used "generic" for derived classes
ef-code-first classes:
the base class
public abstract class BaseClass
{
public int Id { get; set; }
public string Name { get; set; }
}
derived classes:
public class DerivedA:BaseClass
{
public string AValue {get;set;}
...more specific fields
}
public class DerivedB:BaseClass
{
public string BValue {get;set;}
..... more specific fields
}
I call a "generic Method" with these slightly different objects:
System.Data.Entity.DbSet<DerivedA> _dA....
System.Data.Entity.DbSet<DerivedB> _dB....
genericMethod(_dA.Where(a => a.Name.StartsWith("a name")))); //<-contains records
genericMethod(_dB.Where(a => a.Id==5)); //<---- contains records
Both "Where..." contain records in debug (after clicking on Enumerate)
now the method:
public string genericMethod(<IQueryable>BaseClass _myClass)
{
foreach (BaseClass c in _myClass) // <-------class is empty - no records
{
// do something usefull...
}
return someResult
}
But no records are contained, when inside the method.
Is it possible, what I am trying to do...?
Does it make sense?
There are no design-time or compile-time or runtime errors, but the passed object contains no records when passed to the method, but it contained records in the calling statement.
What did I do wrong?
Is there a better approach? -
I need this Method, for manipulation of more than two (maybe ten) derived classes, and therefor I want it "generic".
Thank you!
When faced with something like this, I like to simplify my code.
I would try removing the _dA.Where(a => a.Name.StartsWith("a name")) and _dB.Where(a => a.Id==5) from the method call and put them into variables first (and then pass the variable into the method).
This will allow you to better inspect your code and perhaps shed light on the problem.
add .ToList() to materialize the query before you pass it to the method:
genericMethod(_dA.Where(a => a.Name.StartsWith("a name"))).ToList());
Otherwise you're not really passing the result of the query, you're just passing a query that needs to be evaluated first. ToList() will evaluate it for you. When you look in the debugger watch, it's basically evaluating it for you on the fly, that's why you see rows returned.
After that, change your method to deal with IList instead of IQueryable.
I want to create an error class. And it has some static properties. For example : Message, InnerException, Stacktrace, Source. But I want to add some dynamic properties.
If exception is a FileNotFoundException, I want to add FileName property.
Or if it is a SqlException, I want to add LineNumber property. And I can't inherit that class from Exception because, I return that class from a web service. How can I do that?
C# is a statically typed language. This means you generally cannot dynamically add properties to classes at run-time without some really funky IL injection (which you definitely want to avoid).
In your case it seems that you need to understand exceptions a bit better - we usually throw a specific type of exception to indicate the cause of an exceptional problem. For example, if you are looking for a file and it's not there you would throw a FileNotFoundException or if there is some application-specific problem you could create your own exception class and throw that exception.
Keep in mind that exceptions should be exceptional.
Instead of trying to do something C# currently doesn't handle very well, I suggest you take a somewhat different approach.
Why don't you add those extra properties as data in a dictionary? Your class could expose an interface to get a number of "properties" (in the general sense of the word), i.e. the keys and your calling code could then examine these and use them to look up values as necessary.
you can create type dynamically using new features in C# like anonymous types
I am not sure if you are trying to do some thing similar, but can achieve the requirement as follows
public interface IError { }
public class ErrorTypeA : IError
{ public string Name; }
public class ErrorTypeB : IError
{
public string Name;
public int line;
}
public void CreateErrorObject()
{
IError error;
if (FileNotFoundException) // put your check here
{
error = new ErrorTypeA
{
Name = ""
};
}
elseif (InValidOpertionException) // put your check here
{
error = new ErrorTypeB
{
Name = "",
line = 1
};
}
}
Hope this helps
My take on this would be to use a dictionary where you can store all extra data.
public class Logging
{
private Dictionary<string, string> _ExtraInfo = new Dictionary<string, string>();
public Dictionary<string, string> ExtraInfo {
get { return _ExtraInfo; }
set { _ExtraInfo = value; }
}
}
To use:
Logging MyLogger = new Logging();
MyLogger.ExtraInfo.Add("Filename", thefilename);
MyLogger.ExtraInfo.Add("ClientTime", now);
And so on.
It's very unclear what you're trying to achieve. Reconsider your design in favor of non-static classes and use inheritance.
And you do remember that there are lots of ready-made exception classes in the .NET BCL, right?
Create a new exception type, derived from Exception. Throw this exception, and set the InnerException property to the exception that caused all the ruckus.
You can check for the type of the inner exception and display data accordingly.
If possible, you could of course also just throw the original excpetion to have the caller handling it.