Log4Net, how to add a custom field (variable) to my logging - c#

I'm referring to the excellent post :
Log4Net, how to add a custom field to my logging
But it doesn't give me the entire solution.
No problem to log a string like "This is a test", but If I want to log a variable, it's responding (null).
Here is my snipped code not working:
log4net.GlobalContext.Properties["versionid"] = Variables.IDVERSION;
Here is my working snipped code :
log4net.GlobalContext.Properties["versionid"] = " This is a test";
Although, IDVERSION is a public property systematically updated in my code c#.
Has anyone an idea How to solve this problem? I think I'm near the solution.

At the moment you call this:
log4net.GlobalContext.Properties["versionid"] = Variables.IDVERSION;
The property will hold the value of Variables.IDVERSION at that moment. It won't automagically track updates to the Variables.IDVERSION variable.
So if you set Variables.IDVERSION later in code, you need to do the assignment to Properties["versionid"] again.

When log4net evaluates context properties it calls the .ToString() method of the property value. So you could have dynamic property values if you have a reference as a value (I believe your idversion field is a value type eg. Int?).
See https://logging.apache.org/log4net/release/manual/contexts.html for more details

Related

Epicor 10 How to store data between BPM pre and post processing?

I'm tying to migrate an Epicor V9 system with Progress/ABL code to v10 with C# code. I've got most of it done but I need a way to keep data between a BPMs pre and post processing. The comments in the original ABL code state:
Description : This function stores data from a BPM pre processing action, it does this by using a private-data (storage attribute) on the calling program...
this remains in scope during both the BPM pre and BPM post forward to procedure calls
The Epicor v9 system was set up such that the Quote form calls the BPM pre/post processing in a .p file. The .p file in turned call the code I am trying to migrate in a .i file. It looks to be a simple stack or array of strings.
What would be used in Epicor 10 to persist data between pre/post BPM processing like the .i code did in V9?
You can use CallContext.Properties for this.
In E10.0 the CallContext.Properties was of type Epicor.Utilities.PropertyBag, and items would be accessed as below:
//Add
CallContext.Properties.Add("LineRef", LineRef);
// Get
var LineRef = (string)CallContext.Properties["LineRef"];
// Remove
CallContext.Properties.Remove("LineRef");
E10.1 CallContext.Properties is now of type System.Collections.Concurrent.ConcurentDictionary, which is a .Net built in type and much better documented. However the methods to add and remove entries from it have changes as below:
//Add
bool added = CallContext.Properties.TryAdd("LineRef", LineRef);
// Get
var LineRef = (string)CallContext.Properties["LineRef"]; //Note: Do not use .ToString() this converts instead of unboxing.
// Remove
object dummy;
bool foundAndRemoved = CallContext.Properties.TryRemove("LineRef", out dummy);
To use this your class needs to inherit from ContextBoundBase and implement the only the context bound constructor or you will get 'Ice.ContextBoundBase<Erp.ErpContext>.ContextBoundBase()' is obsolete: 'Use the constructor that takes a data context'
public partial class MyInvokeExternalMethodThing : ContextBoundBase<ErpContext>
{
public MyInvokeExternalMethodThing(ErpContext ctx) : base(ctx)
{
}
In E10.1 you can put any kind of object into this, so if you have an array of strings you don't need to use the old trick of tilde~separated~values.
I don't know about using .i files from E9 but I do know how to persist data between pre and post method directives in E10. Hopefully this helps.
There are a couple of different ways to do this. If when creating the pre-process bpm you chose the "Execute Custom Code" option. You can do it directly in your code using callContextBpmData. Almost all of the field names are similar to that of the user fields that E9 used (i.e. Number01, Chracter01, Date01).
In your code if you are setting text you could simply type:
callContextBpmData.Character01 = "some text";
Alternatively you could set it directly in the bpm designer without any code. In the designer left window pane, scroll all the way to the bottom, you should see something called "Set BPM Data Field". Drag it into the design area. After dragging it into the designer area you should see the option to set a field and its value in the bottom window pane. Select the field, then when you select "value" you are taken to a window similar to baq calculated field designer. You can use static data or use the data in the business object to calculate a value.

If I have default value set as NULL at database, can I ignore while I adding it in c#? via using MVC4

This is the example what I had done on my program.
Currently I had set my database for accepting the datetime Allow NULL and also default value as NULL.
The datetime i set it to nullable like this:
System.DateTime? EntryTime
Then here is my code in MODEL, I do it in the model so that every function who need it can use it.
UserLogin newItems = db.MyItems.Create();
newItems.Id = id;
//newItems.EntryTime = null;
db.UserLogins.Add(newItems);
db.SaveChanges();
Even I didnt commented it, it still goes into the same error result.
when I come to update the data into database it give me "System.Data.Entity.Validation.DbEntityValidationResult" error.
I totally out of idea. Can someone help me?
EDIT 1 I made a mistake on variable.
The only given error is System.Data.Entity.Validation.DbEntityValidationResult and no detailed information given, that's why I am totally out of idea.
Most ORMs won't care about the default value on the table; they care about the object - and the object has a value (a null in this case), whether or not you specify it explicitly. So typically, it will dutifully pass down the null as part of the insert, and the default value will not be used. There may be ways of overriding this in some ORMs, but personally I wouldn't count on it.
Have you tried inserting the data with insert statement?
INSERT INTO `table` (id) VALUES ('id_values');
But I guess you'll have to create a custom module for this. With my MVC application, I use the service-repository approach. Entity Framework is so frustrating.

"Operation is not valid due to the current state of the object." when I attempt to unseal a field on a list

I have a few fields on a list that was created using a schema. The schema and list seem to have gotten out of sync, so when I try to change attributes for a field on the schema, those changes are not reflected on the list, unless they are additions (ie, new fields).
I have a few Sealed fields that I need to unseal. But when I attempt to set Sealed=false, either using SharePoint Manager, or using a utility I wrote, I get the error:
"Operation is not valid due to the current state of the object." I can't seem to find any more usable information about the error.
On my utility, this happens on the line:
field.Sealed = false;
I haven't even gotten to the point of trying to update the field before an exception is thrown. field.SchemaXml looks fine too. I don't see anything wrong with it.
This is happening on multiple fields in this list.
Anyone know what to do?
What is the error and what is the field that is failing?
According to MSDN, you cannot change out of the box or external data fields:
InvalidOperationException: An attempt is made to assign a value to a field type that is built into SharePoint. The true/false value of such fields must remain at its factory setting.
NotSupportedException: An attempt is made to assign false when the SharePoint field is an external data column.
Update (to highlight information that might be hidden in the comments):
Call SPBuiltInFieldId.Contains to avoid (or detect) InvalidOperationException. The Sealed property cannot be set if SPBuiltInFieldId.Contains returns true.
Following up on Rich's answer, if you need to modify a column that is in the SPBuiltInFieldId collection, you can set the GUID of the column to new GUID() during runtime then make any changes to the column you need. Be careful, there is a reason that Microsoft attempts to lock you out of editing these columns. I needed to fix the list relationship for the Resources (Facilities) column in my group calendar and this allowed me to do so.

NHibernate entity design with a private member

In my database I want to save the user GUI settings for one of the "views", as a semicolon-separated string, i.e. : "1;31;5;411;".
I use NNibernate for this project, and this is the mapping and the code for this specific private member;
C# entity code for User.Settings
private string _linkConsole = "0";
[DataMember]
public LinkConsole LinkConsole
{
get { return new LinkConsole(_linkConsole); }
set { _linkConsole = value.GetSqlString(); }
}
XML mapping:
<property name="LinkConsole" type="System.String" access="field.camelcase-underscore" not-null="true"/>
LinkConsole has a lot of public methods for GUI-specific settings, which is toggling the values of certain private members.
When its time to save this settings to the database, .GetSqlString(); formats the string and writes it to the private member _linkConsole , which is the private member exposed to NHibernate & the database.
Problem:
When I try to do something with the GUI, i.e.:
User.Settings.LinkConsole.SetRightPaneContent(50);
This is never stored on the object LinkConsole, and I can't seem to figure out why?
When I set a breakpoint, I get a message in Visual Studio stating:
Your step-into request resulted in an automatic step-over of a property or operator
Maybe this is a result of the problem, that I'm designing this in a wrong way?
If so, is it possible to achieve this in combination with a private string member?
Any help would be greatly appreciated! Thanks! :-)
Have you considered implementing a custom IUserType for LinkConsole for use as the NHibernate type?
The use case you're describing is exactly what IUserType is for.
This isn't really an NHibernate issue. LinkConsole is a reference type. If you set a member of it, it isn't going to call the set method on the property you got it from, it's going to set the value on the instance that was returned from the original get. If you want this code to work, you'd need to get a new LinkConsole instance from the User, call the methods to set the settings, then set the LinkConsole property of the user to your configured instance.
The problem is probably with how you are setting the private variable that is being written to the database. Without seeing your code I can't be sure but look at the following article to be able to step into properties with visual studio:
http://msdn.microsoft.com/en-us/library/cc667388.aspx

Why should I use an automatically implemented property instead of a field?

Between these two:
With Property:
class WithProperty
{
public string MyString {get; set;}
}
With Field:
class WithField
{
public string MyString;
}
Apparently I'm supposed to pick the first one. Why?
I've heard the argument that the point here is to allow interface changes, but
if I have the second one, and change it to the first one, no other code should
ever have to change. When recompiled everything's just going to point to the
property instead.
Am I missing something important here?
The most important difference is the fact, that if you use a field, and later need to change it to a property (say, to enforce some validation), then all libraries calling your code will need to be recompiled. It's true that you can compile the exact same code if the name stays the same - but the consumers of your code will still need to be recompiled. This is because the IL generated to get the value is different between a field and a property. If it already is a property, you can make a change without forcing consumers of your code to change.
This may or may not be an issue for you. But the property is almost the same amount of code, and is considered best practice. I would always go for the property.
The property can be changed later if you need to add validation or other logic without breaking other assemblies.
Also, the property can be used with databinding.
The important part you are missing is the gravity of this statement:
When recompiled
When your code point to a field and you change it to point to a property of the same name, the C# itself doesn't change, but the resulting IL does - it generates a method call to the getter or setter as appropriate.
Not every app has all of it's pieces contained in a single distributed unit. Many apps rely on interfaces for pluggability/expandability. If you have an app with an interface to a field and you want to change it to a property to take advantage of the power of properties, the app has to be recompiled and redistributed. You might as well just make it a property in the first place.
With a property, you can easily extend it to include new logic.
For example, if you need to add validation logic to the set.
This article goes into several additional reasons why you should prefer properties:
http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx

Categories