I am building a library which can parse complex files into a datamodel. Inside the library during parsing and during some other operations on the data structure I am building certain messages might occur (info, warnings, errors).
I need a way for the user of the library to fetch those messages. All stuff I am thinking about boils down to some static Event or a static list of those messages. But I want each object of the datastructure to have its own message queue.
An example:
class Program
{
static void Main(string[] args)
{
CalibData cd1 = new CalibData();
cd1.LoadFile(#"C:\tmp\file.ext");
var messageList = cd1.GetMessages();
cd1.DoOtherStuff();
CalibData cd2 = new CalibData();
cd2.LoadFile(#"C:\tmp\file2.ext");
cd2.LoadFile(#"C:\tmp\file3.ext2");
messageList = cd1.GetMessages(); //Do other stuff could have produced new Messages
var messageList2 = cd2.GetMessages();
}
}
Do you have any suggestions on how to implement such behavoir? I need something which is globally accessibly inside each instance, but each instance has another global messenger.
Additional Information:
Internall I am using an ANTLR Parser which generates a lot of objects (50.000+). Once the datastructure is created a lot of crossreferences are being set on the objects, etc. My main problem is, that I either have to create a static member to handle this, or from LoadFile() pass a messenger very deep into my function calls of the parser, cross referencing etc. In my opionion both is a rather bad choice. Changing the design is not an option since there is more to my problem. The datastructure is stored in 2 files (1 file = description, other file = data). So I can call something like
CalibData cd = new CalibData();
cd.LoadFile("description file"); //after this call the datastructure is built, but it hasn't got any value data yet
cd.LoadFile("data file") //now the structure also has value data
cd.ClearData();
cd.LoadFile("yet another data file"); //same structure different data
It looks like your LoadFile method currently doesn't return anything - why not make it return a data structure containing the errors, warnings etc? No need for anything global or static - or even persistent. Just the result of a method call.
In fact, I'd probably change this slightly so that a separate class (rather than the model itself) was responsible for loading, and the LoadFile call would return a result containing:
Information and errors
The resulting model object
That way any time you have a model you know it contains actual data - rather than it being "ready to load" as it were.
Related
I want to be able to send two different JSON messages on one queue. How do I, in C#, determine what type of message was received so that I can deserialize the message to the proper object? Should I use a message header or create another queue? A queue per message type seems excessive to me. Thanks!
Extra Details:
I have a Windows service that processes "runs". A run ID is assigned by another system and the ID is dropped on a queue. My service picks up the ID and starts work. An object is created for each run. Right now, if I want to cancel work, I have to stop the service. But, that stops all work. I wanted to add a CancelRun type method, but all I need to the run ID. So, I could use the exact same JSON (so same class). Two queues wouldn't be horrible, but I thought it might be clever to add the type or something to a custom header.
Here's what I went with. I like this technique because I'm not adding stuff to the JSON that isn't part of the model.
IBasicProperties props = model.CreateBasicProperties();
props.Headers = new Dictionary<string, object>();
props.Headers.Add("RequestType", "CancelRunRequest");
Then, on the receiving side, I do this (I'm raising an event with a custom EventArg obj):
// Raise message received event
var args = new MessageReceivedArgs();
args.CorrelationId = response.BasicProperties.CorrelationId;
args.Message = Encoding.UTF8.GetString(response.Body);
args.Exchange = response.Exchange;
args.RoutingKey = response.RoutingKey;
if (response.BasicProperties.Headers != null && response.BasicProperties.Headers.ContainsKey("RequestType"))
{
args.RequestType = Encoding.UTF8.GetString((byte[])response.BasicProperties.Headers["RequestType"]);
}
MessageReceived(this, args);
model.BasicAck(response.DeliveryTag, false);
Elsewhere in the project:
private void NewRunIdReceived(object p, MessageReceivedArgs e)
{
if(e.RequestType.ToUpper() == "CANCELRUNREQUEST")
{
// This is a cancellation request
CancelRun(e);
}
else
{
// Default to startrun request for backwards compatibility.
StartRun(e);
}
}
If an order or receiving and processing of these messages is not an issue I would like to suggest using separate queues for each type, it's not a problem for rabbit to handle tons of queues.
If not, the order is crucial for you, you can put marker in header of the message defining it's type, however this will bind your Business Logic with transportation layer. In case you will want to change the transportation layer later in your application, you will have to adopt this section of code to keep it work. Instead of this you can make some sort of wrapper for both of those object types which hides the internal content, looks the same and can desalinize itself in type it contains.
Adding runtime type information as suggested by sphair works, but I dislike doing that since you loose the portability value of having a weak type. You might also consider having the deserialized C# object be generic enough to handle all the flavors, and then branch from there.
You can add all of them into array and then deserialise based on type, you will have to add type property manually, or you could create Object IHaveType and then inherit from it in objects that are being used, but that's a horrible way to do this.
ObjectType1 : HaveType
public class HaveType { public string Type { get { this.GetType(); }}}
Json
[{Type: 'ObjectType1', ...[other object stuff]},{Type : 'ObjectType2',...}]
JSON does not say what a type it was serialized from, unless the serializer itself adds some information to the JSON.
You could add some structure to the JSON so you are able to deduct the type.
I'm writing an Windows Forms application that reads a file, processes it and then commits the changes.
Depending on some circumstances, when i click on "Process button" from the form i want it to interact with a specific object, for example depending on the extension of the file, the file gets processed by a specific class that handles that type of file.
In terms of application architecture, what's the best way to do this?
So for example a .txt file is processed by a TextParser, a .csv file is processed by a CSVParser, a .doc file is processed by a MSWordParser, everything else is processed by a GenericParser, etc.?
Well, the first thing would be to create an interface, i.e. IParser so that every class has a .Parse(file) method.
Next is the task of matching up the file extension strings with classes. The first thing that comes to mind for me is a Dictionary. The key would be the file extension as a string and the value would be a parser for that type of file extension. Before doing any processing you would populate the dictionary with all of the file extensions you wish to support.
Some assumptions for this to work well:
-You don't have a very large number of supported file extensions.
-One instance of the parser can be used repeatedly
-new-ing a parser isn't particularly expensive; there is minimal initialization beyond what the language needs to do to new an object.
I would go with something like a Factory pattern.
public interface IFileParser
{
void perse(string fileToParse);
}
public static class FileParserFactory
{
public static IFileParser GetParser(string fileToParse)
{
FileInfo file = new FileInfo(fileToParse);
IFileParser parserToReturn = null;
switch (file.Extension.ToLower())
{
case "csv": parserToReturn = new CSVFileParser(fileToParse);
break;
case "txt": parserToReturn = new TextFileParser(fileToParse);
break;
}
return parserToReturn;
}
}
I have a controller circuit that I can communicate with via serial port and I would like to write a class library for it. I figured it is far easier calling a method (and far more readable) than repeatedly hard-coding lengthy character strings. Anyway, the controller comes pre-programmed with ~100 get/set functions separated into three categories: Sensor Settings, Output Settings, and Environment Settings. These functions are used to get or set the controller's settings. I was wondering what the "best" or "accepted" class organization would be?
All the functions belong to the same controller and use the same serial port so I figured that Controller would be the top level class. Within this class, I setup a SerialPort instance and created a simple send/receive method using the instance: string SendReceive(string commandString).
Because I really don't want to have ~100 functions and properties in the single class, I tried creating some nested classes (SensorSettings, OutputSettings, and EnvironmentSettings) and placing the respective functions within them. When I tried to build, however, I received a compile error stating that I attempted to access a higher level, non-static method (SendReceive(string commandString)) from within one of the nested classes.
Each of the various methods has a unique and variable send/receive command so I would create the command string within the method, call SendReceive, and process the returning command. Is there any way to do this?
I would like to use properties to work my way down to get/set the various settings. For example...
controllerInstance.SensorSettingsProperty.Units; // Units in use.
or...
controllerInstance.OutputSettingsProperty.GetOutput(sensor1); // Get sensor 1 output.
...but all of these require the use of the same serial port and SendRecieve.
It sounds like you need to make objects for each command, and then use your controller to send commands.
Example:
public class GetSensorReadingCommand
{
public GetSensorReadingCommand(Sensor sensor, SerialController controller)
{
// Set up command
}
public int Execute()
{
// Call controller.SendReceive with whatever, get or send stuff
}
}
Then you would simply make new objects every time you want to do a function.
SerialController controller = new SerialController(somePortNumber);
GetSensorReadingCommand command = new GetSensorReadingCommand(Sensor.Sensor10, controller);
int reading = command.Execute();
You would follow a pattern like that for each command you can send. If it's not a known at compile type sensor number, instead of using an enum, provide an integer.
You'll end up with a lot of small code files instead of a bunch of large ones. In addition, you can tailor each command with logic specific to it's functioning.
Let's say we have a business object, let's call it a Foo, which contains an ordered list of Bars. We pass this Foo around as XML.
We have a class which deserializes a Foo XML node (FooXMLDeserializer) which itself uses a class which deserializes the child Bar XML nodes (BarXMLDeserializer).
Now, I'm adding some functionality to the BarXMLDeserializer that maintains some state such that if FooXMLDeserializer is called on two separate Foo nodes without reseting the BarXMLDeserializer's state, the results may be invalid. BarXMLDeserializer does not know when it has processed the final Bar in a Foo.
Is there some way that I can design the BarXMLDeserializer class to communicate to developers working on consuming classes that it has state and must be reset for each Foo?
Further info:
My change solves a minor enough problem in our code that I won't be able to convince my manager to let me spend X days redesigning the whole system to nicely handle this case.
If it matters, BarXMLDeserializer keeps is state in a BarStateTracker class which is internal to it.
Programming in C#, but looking for a more general solution.
Thanks.
Expose your serializer only as a static method:
// no public constructor, etc
var deserializer = BarXMLDeserializer.CreateNew();
Then, when you have finished deserializing data, mark a field in your object. If the field is set, throw an exception if the same instance is used to deserialize more data when the deserialize method is called.
if(IsInstanceExhausted)
throw new InvalidOperationException("You must use a fresh instance.");
They'll figure it out after their first exception. In addition, mark your class as IDisposable so that code naturally uses using statements:
using(var deserializer = BarXMLDeserializer.CreateNew())
{
}
The list goes on of additional ways. ALTERNATIVELY, you could simply design your Deserializer to clear it's state or reset after a deserialization attempt, or to clear the state at the beginning of a deserialization attempt.
I'm wondering how others deal with trying to centralize MessageBox function calling. Instead of having long text embedded all over the place in code, in the past (non .net language), I would put system and application base "messagebox" type of messages into a database file which would be "burned" into the executable, much like a resource file in .Net. When a prompting condition would arise, I would just do call something like
MBAnswer = MyApplication.CallMsgBox( IDUserCantDoThat )
then check the MBAnswer upon return, such as a yes/no/cancel or whatever.
In the database table, I would have things like what the messagebox title would be, the buttons that would be shown, the actual message, a special flag that automatically tacked on a subsequent standard comment like "Please contact help desk if this happens.". The function would call the messagebox with all applicable settings and just return back the answer. The big benefits of this was, one location to have all the "context" of messages, and via constants, easier to read what message was going to be presented to the user.
Does anyone have a similar system in .Net to do a similar approach, or is this just a bad idea in the .Net environment.
We used to handle centralized messages with Modules (VB). We had one module with all messages and we call that in our code. This was done so that we change the message in one place (due to business needs) and it gets reflected everywhere. And it was also easy to handle change in one file instead of multiple files to change the message. Also we opened up that file to Business Analysts (VSS) so that they can change it. I don't think it is a bad idea if it involves modules or static class but it might be a overkill to fetch it from DB.
HTH
You could use resource files to export all text into there (kinda localization feature as well). Resharper 5.0 really helps in that highlighting text that can be moved to resource.
Usually it looks like this:
Before: MessageBox.Show(error.ToString(), "Error with extraction");
Suggestion: Localizable string "Error with extraction"
Right click Move to Resource
Choose resource file and name (MainForm_ExtractArchive_Error_with_extraction), also check checkbox Find identical items in class ...
Call it like this MessageBox.Show(error.ToString(), Resources.MainForm_ExtractArchive_Error_with_extraction);
Best of all it makes it easy to translate stuff to other languages as well as keeping text for MessageBox in separate Resource. Of course Resharper does it all for you so no need to type that much :-)
I suppose you could use a HashTable to do something similar like this, this can be found in:
using System.Collections;
To keep it globally accessable i was thinking a couple of functions in a class holding the hashtable to get/set a certain one.
lets see now.
public class MessageBoxStore
{
private HashTable stock;
public string Get(string msg)
{
if (stock.ContainsKey(msg))
return stock[msg];
else
return string.Empty;
}
public string Set(string msg, string msgcontent)
{
stock[msg] = msgcontent;
}
}
or something like that, you could keep multiple different information in the hashtable and subsequently compose the messagebox in the function too.. instead of just returning the string for the messagebox contents...
but to use this it would be quite simple.
call a function like this on program load.
public LoadErrorMessages()
{
storeClass = new MessageBoxStore();
storeClass.Set("UserCantDoThat", "Invalid action. Please confirm your action and try again");
}
for example, and then.
MessageBox.Show(storeClass.Get("UserCantDoThat"));
i put this in a new class instead of using the HashTable get/set methods direct because this leaves room for customization so the messagebox could be created in the get, and more than 1 piece of information could be stored in the set to handle messagebox title, buttontype, content, etc etc.