i have a custom object like this.
public class Propertey
{
public string Key { get; set; }
public string Value { get; set; }
}
public class MonitoringEvent
{
public string AppName { get; set; }
public string Service { get; set; }
public string Fuction { get; set; }
public string CorrelationId { get; set; }
public List<Propertey> Properties { get; set; }
public string EventName { get; set; }
public DateTime TimeStamp { get; set; } = DateTime.UtcNow;
}
and this object gets populated from outside the system and in my function app i am trying to log it in App Insights.
[FunctionName("EventMonitoring")]
public async Task Run([ServiceBusTrigger(
"cta-event-monitoring",
"monitoring",
Connection = "ServiceBusConnectionString",
IsSessionsEnabled = false)]string mySbMsg, ILogger log)
{
try
{
MonitoringEvent me = JsonConvert.DeserializeObject<MonitoringEvent>(mySbMsg);
log.LogInformation("MonitoringEvent", me);
}
catch (Exception ex)
{
log.LogError("MonitoringEventError",ex);
}
}
when i see App insights i cant see properties like "AppName" "Service" etc in app insights. where can i find them ? later i want to be able to query on them as well. but all i see in app insights is something like this
You need to log using a log message template. The message template can contain placeholders for which arguments are provided. Use names for the placeholders. In your case that means you need to add a named template position
log.LogInformation("MonitoringEvent {Event}", me);
This will create a custom property "Event" in the trace of application insights.
In your current code you do not provide a placeholder so the argument cannot be put somewhere and is ignored.
Also, do mind that application insights will probably use .ToString() on any object arguments so your best bet will be to just use mySbMsg as the argument.
Related
My application reads in JSON from disk and deserialising using JSON.net; which is working fine.
My JSON is laid out like this:
{
"driver": {
"driverTag": "blah_blah",
"driverName": "Blah Blah",
"driverTransport": "serial-device"
},
"devices": [
{
"deviceName": "Dev1",
"deviceTag": "DEV1",
"deviceStartMode": "Auto"
},
{
"deviceName": "Dev2",
"deviceTag": "DEV2",
"deviceStartMode": "Auto"
}
]
}
Based on the "driverTransport" value, I deserialise to either a SerialDriverConfig, TelnetDriverConfig, SNMPDriverConfig... etc class.
As the "driver" properties will be the same for every driver, no matter the transport type, I have a "DriverConfigTemplate" class. The "devices" will differ from JSON file to JSON file and have specific properties for that transport type (i.e. a serial device will have properties like "serialPortName", "serialBaudRate" etc.)
I have a "DriverConfig" interface, where T is "DeviceConfig".
public interface DriverConfig<T> where T : DeviceConfig
{
DriverConfigTemplate driver { get; set; }
List<T> devices { get; set; }
}
My device config is as follows:
public class DeviceConfig : IDeviceConfig
{
public string deviceTag { get; set; }
public string deviceName { get; set; }
public string deviceStartMode { get; set; }
}
Now; the problem part. When I am deserialising, I check the transport type before hand and determine the class to use; i.e for a serial driver I will use the "SerialDriverConfig" class and deserialise using the "SerialDeviceConfig":
public class SerialDeviceConfig : DeviceConfig
{
public int serialComPort { get; set; }
public int serialBaudRate { get; set; }
public int serialDataBits { get; set; }
public string serialParity { get; set; }
public string serialStopBits { get; set; }
public string serialHandshake { get; set; }
public int serialReadTimeout { get; set; }
public int serialWriteTimeout { get; set; }
public bool serialRtsEnable { get; set; }
public bool serialDtrEnable { get; set; }
}
My "SerialDriverConfig" class looks like this:
public class SerialDriverConfig : DriverConfig<SerialDeviceConfig>
{
public DriverConfigTemplate driver { get; set; }
public List<SerialDeviceConfig> devices { get; set; }
}
Again, this is fine and the JSON.net deserialiser does its job perfectly.
I have a function that gets called when the JSON config file has been loaded and validated against its respective schema, then passed on to a "DeserialiseDriverConfig" function where I am trying to return the derived driver object; which is where I am stuck :(
private DriverConfig<DeviceConfig> DeserialiseDriverConfig(string _json, string _driverTransport)
{
switch (_driverTransport)
{
case "serial-device":
try
{
SerialDriverConfig _serialDriverConfig = JsonConvert.DeserializeObject<SerialDriverConfig>(_json);
if (_serialDriverConfig != null)
{
return _serialDriverConfig;
}
}
catch (Exception e)
{
//Blah blah blah
}
break;
}
return null;
}
I have been stuck on this one for a few days, have tried many things and this is where I have ended up. I am getting "Cannot implicitly convert type "SerialDriverConfig" to "DriverConfig". An explicit conversion exists (are you missing a cast?)" So I understand why this error is occurring, but cannot get around it.
Hope my code makes sense and someone can help me out here?
You can change your DriverConfig class to be non-generic
public interface DriverConfig
{
DriverConfigTemplate driver { get; set; }
List<DeviceConfig> devices { get; set; }
}
and instead of using derived classes (SerialDriverConfig etc.) you can set Json.net to deserialize to the correct DeviceConfig type based on either having a $type attribute in your JSON like this or using a custom JsonConverter similar to this
I'm not sure if this solution fits your need but if you create your method and SerialDriverConfig with using generic type T you can use your interface as a returning type. Can you try the code below;
Your Method:
private static DriverConfig<T> DeserialiseDriverConfig<T>(string _json, string _driverTransport)
{
switch (_driverTransport)
{
case "serial-device":
try
{
SerialDriverConfig<T> _serialDriverConfig = JsonConvert.DeserializeObject<SerialDriverConfig<T>>(_json);
if (_serialDriverConfig != null)
{
return _serialDriverConfig;
}
}
catch (Exception e)
{
//Blah blah blah
}
break;
}
return null;
}
SerialDriverConfig Class:
public class SerialDriverConfig<T> : DriverConfig<T>
{
public DriverConfigTemplate driver { get; set; }
public List<T> devices { get; set; }
}
Also you should consider changing DriverConfig<T> interface approach because if you leave it as-is you will have boxing issue. If you do not need you may remove where T : DeviceConfig from your interface or modify it according to your current circumstances.
Hope this helps, please let me know if this works for you
I am currently developing a file indexing system. I have an interface IDiskDrive that can get immediate file items (files/folders). The interface definition is as follows...
public interface IDiskDrive
{
bool IsReady { get; }
string Name { get; }
string VolumeLabel { get; }
string VolumeLabelName { get; }
DiskDriveType Type { get; }
FolderPath RootFolder { get; }
DiskDriveUsage Usage { get; }
IEnumerable<IFileItem> GetImmediateFileItems(FolderPath path);
}
The ability to read all file/folders is complete and works correctly. Now, I need to actually index the file files and folders. Looking ahead I know I will need some reporting tools. This leads me to think I need another abstraction, based upon IDiskDrive that can read/populate. I also need the ability to select drives for indexing.
My question is should my new class inherit IDiskDrive or should I use composition (possibly a decorator)?
// inheritance
class IndexedDiskDrive : IDiskDrive
{
public IndexedDiskDrive(IDiskDrive drive)
{
...
}
public int Id {get; internal set; } // database id
public bool Selected { get; internal set; }
public DateTime? DateLastIndexed { get; internal set; }
// IDiskDrive implementation
public bool IsReady
{
get { return this.Drive.IsReady; }
}
}
or composition...
class IndexedDiskDrive
{
public IndexDiskDrive(IDiskDrive drive)
{
this.Value = drive;
}
public IDiskDrive Value
{
get;
private set;
}
// additional properties
public int Id { get; internal set; }
public bool Selected { get; internal set;}
public DateTime DateLastIndexed { get; internal set; }
}
Note:
I need access to the underlying IDiskDrive for the UI.
For example, I request user to select drives to index. I initially supply a list of local drives and the ability to add network drives. To try and keep code simple, I thought the idea of a new class with a selected property might help.
This allows the GUI to enumerate a list of IndexedDiskDrives and set/clear the select property.
In both examples you expose the IDiskDrive object from the other object. In the first case you inherit from the same inteface, which means you expose the same methods and in the other case you expose the object via a property.
I don't see a reason yet why you want to do this.
It sounds like a typical constructor DI case to me. Just have a new interface for your new class which is doing a different job and hence requires a different contract, and if it needs the IDiskDrive object as a dependency, then just inject it via the constructor and leave it as it is.
P.S.: I know this is not something you have asked, but you might be interested in Lucense.NET, which is a .NET library to index files. They might have already solved your problem for your:
http://lucenenet.apache.org/
EDIT:
From your current class design I would do the following:
void Main()
{
// Use IoC container in real app:
var diskDrive = new DiskDrive(...);
var fileIndexer = new FileIndexer();
var fileItems = diskDrive.GetImmediateFileItems(filePath);
fileIndexer.IndexFiles(fileItems);
}
// Define other methods and classes here
public interface IDiskDrive
{
bool IsReady { get; }
string Name { get; }
string VolumeLabel { get; }
string VolumeLabelName { get; }
DiskDriveType Type { get; }
FolderPath RootFolder { get; }
DiskDriveUsage Usage { get; }
IEnumerable<IFileItem> GetImmediateFileItems(FolderPath path);
}
public interface IFileIndexer
{
void IndexFiles(IEnumerable<IFileItem> files);
}
public class FileIndexer : IFileIndexer
{
public void IndexFiles(IEnumerable<IFileItem> files)
{
// do stuff
}
}
Got a question. I get this error and I know it is due to the fact that int32 has a number limit of 2147483647. But I don't know why I am getting this error when the value in question (a telephone number of 11 digits) is defined as a string in our SQL database, a string in our web service and a string in our web application.
I assume it is something to do with the way the service serialises and deserialises data over a connection, but I was wanting to know if there is a way to force Number to use only the string instead of parsing it when deserialisation happens. Or even get it to parse as int64.
Here is the error exception. I removed the namespace and service name. It is the property Number that is causing the problem.
There was an error deserializing the object of type .".ClientPhone[]. The value '07721545554' cannot be parsed as the type 'Int32'."
And here is the code for the service and the service interface.
[DataContract]
public class ClientPhone
{
[DataMember]
public int? ClientNumberID { get; set; }
[DataMember]
public int? RefID { get; set; }
[DataMember]
public string Number { get; set; }
[DataMember]
public string NumberType { get; set; }
[DataMember]
public bool? PrimaryNumber { get; set; }
}
public partial class ClientNumberEntity
{
public int ClientNumbersID { get; set; }
public Nullable<int> RefID { get; set; }
public string ClientNumberType { get; set; }
public string ClientNumber { get; set; }
public Nullable<bool> PrimaryNumber { get; set; }
public virtual ClientDataEntity ClientData { get; set; }
}
public List<ClientPhone> GetClientsPhoneByReference(int _reference)
{
OurDatabaseEntities context = new OurDatabaseEntities();
var phoneEntity = (from c in context.ClientNumberEntities
where c.RefID == _reference
select c).ToList();
if (phoneEntity != null)
{
return TranslateClientPhoneEntityToPhoneNumberList(phoneEntity);
}
else
throw new Exception("Unable to get phone data");
}
private List<ClientPhone> TranslateClientPhoneEntityToPhoneNumberList(List<ClientNumberEntity> numberEntities)
{
List<ClientPhone> phoneList = new List<ClientPhone>();
foreach (ClientNumberEntity numberEntity in numberEntities)
{
ClientPhone phoneListMember = new ClientPhone();
phoneListMember.ClientNumberID = numberEntity.ClientNumbersID;
phoneListMember.RefID = numberEntity.RefID;
phoneListMember.Number = numberEntity.ClientNumber;
phoneListMember.NumberType = numberEntity.ClientNumberType;
phoneListMember.PrimaryNumber = numberEntity.PrimaryNumber;
phoneList.Add(phoneListMember);
}
return phoneList;
}
Any advice on a solution would be greatly appreciated! Thanks :)
Got a solution, albeit it's more stupidity on my end.
I didn't realise that my .EDMX entity diagram hadn't been updated with the new values from the database (I had to manually delete the entity and re-add it to force changes).
After re-compiling and updating the service reference, it worked.
I have this issue where I'm sending a request for a JSON Feed. The issue is that the feed has a dynamic header (i.e. when I send a request for "testinput1" the header response will be testinput1.
Therefore I need to make my RootObject dynamic, but I'm not sure how, could you please help me?
I've entered the troublesome part of the code below
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
textBlock1.Text = "Details Loaded.";
short_description.Text = feed.testinput1.short_description; // can I make testinput1 a constant? its based on code below
});
public class Event
{
public string description { get; set; }
public string datetime { get; set; }
}
public class TrackCode
{
public string short_description { get; set; }
public List<Event> events { get; set; }
}
public class RootObject
{
public string tracker;
public TrackCode testinput1// This needs to be based on user input each time
{
get; // Can I do something here to make sure that the "testinput1" changes each time?
set; // And create a constant that can be referred to?
}
}
Hopefully I can do something like this:
short_description.Text = feed.trackcode.short_description; // this is a constant
public class RootObject
{
public string tracker = "AB123456789NZ"; // This is the variable that changes
public TrackCode trackcode // this becomes a constant
{
get { return tracker; } // uses tracking number as value for JSON when it retrieves it
set { tracker = value;}
}
}
Where have I gone wrong? Thankyou!
I'm trying to figure out what the proper syntax is to achieve a certain API goal, however I am struggling with visibility.
I want to be able to access a Messenger instance's member like msgr.Title.ForSuccesses.
However, I do not want to be able to instantiate Messenger.Titles from outside my Messenger class.
I'm also open to making Messenger.Titles a struct.
I'm guessing I need some sort of factory pattern or something, but I really have no idea how I'd go about doing that.
See below:
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this should be allowed
var t = new Messenger.Titles(); // this should NOT be allowed
}
}
public class Messenger {
// I've tried making this private/protected/internal...
public class Titles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
// I've tried making this private/protected/internal as well...
public Titles() {}
}
public Titles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
You just need to make Titles private and expose an interface instead of it.
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this is allowed
var t = new Messenger.Titles(); // this is NOT allowed
}
}
public class Messenger {
public interface ITitles {
string ForSuccesses { get; set; }
string ForNotifications { get; set; }
string ForWarnings { get; set; }
string ForErrors { get; set; }
}
private class Titles : ITitles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
}
public ITitles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
If you make the Titles constructor internal you will be able to create instances of it within your assembly only. If it is an API, perhaps that will be protected enough? You can see this pattern within the BCL (such as HttpWebRequest that can be created only through calls to WebRequest.Create).
Why Would I Ever Need to Use C# Nested Classes Nested type is never intended to be initialized from external type.
Well, you could make Titles a struct and make the constructor either public or internal. In that way, every time a client gets a copy of the Titles instance through the Title property, they will be getting the value, not the reference. They could modify that value, but to apply that change to the internal state of your object, they would need to be able to set the value back again through the Title property. They can't, because you have the Title setter marked private.
You will have to do the same when you change a value internally. For example:
// Your constructor...
public Messenger()
{
Titles t = new Titles();
t.ForSuccesses = "blah";
Title = t;
}
You can do this internally because you have access to the private setter for the Title property.
The main downside is that it might confuse the clients of your framework a bit because it looks like you can set the values of the Titles instance, but there is no real way for them to commit that change back to the Messenger class.