Callee taking action based on type of caller - oop

I would like to know if there is some alternate better pattern other than below where an object passes itself as a context to another object which in turn uses the context or lack as logic to build the necessary output. I have tried making the caller/sender an interface and pass itself as an interface but the real question is is it good practice for the called object to even know who its caller is, i.e. to distinguish it from other callers and take separate actions if necessary? Am I missing a piece to the puzzle?
Caller (CGQuery):
public string RenderForLoop()
{
...
sb.Append(string.Join("",this.ContentIsCGExpressions.Select(exp => exp.GetProcessedExpression(this))));
...
Callee (CGExpression):
public string GetProcessedExpression(object context = null)
{
...
retv = ReplaceCodes(retv, context);
...
private string ReplaceCodes(string retv, object context = null)
{
... retv = ReplaceContextSequenceCode(retv, context);
return retv;
}
...
private string ReplaceContextSequenceCode(string retv, object context = null)
{
var _regx = new Regex("(?i)<q_ctx_seq>");
var _matchresult = _regx.Match(retv);
while (_matchresult.Success)
{
string replacement = FetchContextSequenceQueryTableFieldExpression(context);
retv = retv.Replace(_matchresult.Groups[0].Value, replacement);
_matchresult = _matchresult.NextMatch();
}
return retv;
}
private string FetchContextSequenceQueryTableFieldExpression(object context = null)
{
if (context != null && context is CGQuery)
{
return ((CGQuery)context).FetchContextSequenceQueryTableFieldExpression();
}
return this.CGStatementsUsedAsParamsFor.Any() ?
this.CGStatementsUsedAsParamsFor.Single().FetchContextSequenceQueryTableFieldExpression(context)
:
this.CGQueriesContentFor.Single().FetchContextSequenceQueryTableFieldExpression();
}
It's this line in the above that I'm concerned about (seems to violate encapsulation?)
if (context != null && context is CGQuery)
{
return ((CGQuery)context).FetchContextSequenceQueryTableFieldExpression();
}
sorry I don't know how to highlight the code in the main block.

What about letting the caller deliver an object to the callee containing the action to execute? The caller may be queried within this action without the callee being aware of its existence.
Generally I would say it's not good OOP practice to decide behaviour on the class of the calling object.

Related

BoldReports - ReportHelper.GetParametersWithValues() returns parameter collection with empty values

BoldReports ReportViewer Controller:
I'm using the ReportHelper.GetParametersWithValues() function in the OnReportLoaded() method to retrieve the report parameters. It is successfully retrieving the list of parameters, however, only the name attributes are populated - the values are null.
private ReportParameterInfoCollection _rptParamColl;
public void OnReportLoaded(ReportViewerOptions reportOption)
{
_rptParamColl = ReportHelper.GetParametersWithValues(jsonArray, this, _cache);
if (_rptParamColl != null)
{
foreach (ReportParameterInfo rptParam in _rptParamColl)
{
if (rptParam.Name == "OrgID")
{
if (rptParam.Values != null )
{
// perform appropriate validation on rptParam.Values[0]
}
}
}
}
}
In the code sample above, rptParam.Name has a value, but the rptParam.Values is null. I know the values exist, as when I inspect the jsonArray object, they are in there (although oddly, after calling ReportHelper.GetParametersWithValues(), the jsonArray object is cleared? Same also happens when calling ReportHelper.GetDataSources(). This is also a problem, as I want to call both methods, and after calling one, cannot call the other... )
Any ideas what I may be doing wrong?
Using the PostReportAction method you can get the client-side parameter value. Please refer to the below code snippet,
public object PostReportAction([FromBody] Dictionary<string, object> jsonResult)
{
if (jsonResult.ContainsKey("parameters") && jsonResult["parameters"] != null)
{
var parameterValues = Newtonsoft.Json.JsonConvert.DeserializeObject<BoldReports.Web.ReportParameterInfoCollection>(jsonResult["parameters"].ToString());
}
return ReportHelper.ProcessReport(jsonResult, this, this._cache);
}

Outlook Add-In :: COM object that has been separated from its underlying RCW cannot be used

While I have found many instances of this question on SO, none of the solutions I have implemented have solved my problem; hopefully you can help me solve this riddle. Note: This is my first foray into the world of COM objects, so my ignorance is as deep as it is wide.
As a beginning, I am using Adrian Brown's Outlook Add-In code. I won't duplicate his CalendarMonitor class entirely; here are the relevant parts:
public class CalendarMonitor
{
private ItemsEvents_ItemAddEventHandler itemAddEventHandler;
public event EventHandler<EventArgs<AppointmentItem>> AppointmentAdded = delegate { };
public CalendarMonitor(Explorer explorer)
{
_calendarItems = new List<Items>();
HookupDefaultCalendarEvents(session);
}
private void HookupDefaultCalendarEvents(_NameSpace session)
{
var folder = session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
if (folder == null) return;
try
{
HookupCalendarEvents(folder);
}
finally
{
Marshal.ReleaseComObject(folder);
folder = null;
}
}
private void HookupCalendarEvents(MAPIFolder calendarFolder)
{
var items = calendarFolder.Items;
_calendarItems.Add(items);
// Add listeners
itemAddEventHandler = new ItemsEvents_ItemAddEventHandler(CalendarItems_ItemAdd);
items.ItemAdd += itemAddEventHandler;
}
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
Bits not relevant to adding appointments have been redacted.
I instantiate the CalendarMonitor class when I spool up the Add-in, and do the work in the AppointmentAdded event, including adding a UserProperty to the AppointmentItem:
private void ThisAddIn_Startup(object sender, EventArgs e)
{
_calendarMonitor = new CalendarMonitor(Application.ActiveExplorer());
_calendarMonitor.AppointmentAdded += monitor_AppointmentAdded;
}
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
item = null;
}
}
The error is thrown here, where I try to add a UserProperty to the AppointmentItem. I have followed the best example I could find:
private void AddUserProperty(AppointmentItem item, string propertyName, object value)
{
UserProperties userProperties = null;
UserProperty userProperty = null;
try
{
userProperties = item.UserProperties;
userProperty = userProperties.Add(propertyName, OlUserPropertyType.olText);
userProperty.Value = value;
item.Save();
}
catch (Exception ex)
{
Debug.Print("Error setting User Properties:");
PrintToDebug(ex);
}
finally
{
if (userProperty != null) Marshal.ReleaseComObject(userProperty);
if (userProperties != null) Marshal.ReleaseComObject(userProperties);
userProperty = null;
userProperties = null;
}
}
... but it chokes on when I try to add the UserProperty to the AppointmentItem. I get the ever-popular error: COM object that has been separated from its underlying RCW cannot be used. In all honesty, I have no idea what I'm doing; so I'm desperately seeking a Jedi Master to my Padawan.
The main problem here is using Marshal.ReleaseComObject for RCW's that are used in more than one place by the managed runtime.
In fact, this code provoked the problem. Let's see class CalendarMonitor:
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
After the event returns, it tells the managed runtime to release the COM object (from the point of view of the whole managed runtime, but no further).
appointment = null;
}
}
Then, an async event is attached, which will actually return before using the appointment, right at the await line:
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
This method actually returns here. C#'s async code generation breaks async methods at await points, generating continuation passing style (CPS) anonymous methods for each block of code that handles an awaited result.
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
Look, it's releasing the COM object again. No problem, but not optimal at all. This is an indicator of not knowing what is going on by using ReleaseComObject, it's better to avoid it unless proven necessary.
item = null;
}
}
In essence the use of ReleaseComObject should be subject to a thorough review of the following points:
Do I need to actually make sure the managed environment releases the object right now instead of at an indeterminate time?
Occasionally, some native objects need to be released to cause relevant side effects.
For instance, under a distributed transaction to make sure the object commits, but if you find the need to do that, then perhaps you're developing a serviced component and you're not enlisting objects in manual transactions properly.
Other times, you're iterating a huge set of objects, no matter how small each object is, and you may need to free them in order to not bring either your application or the remote application down. Sometimes, GC'ing more often, switching to 64-bit and/or adding RAM solves the problem in one way or the other.
Am I the sole owner of/pointer to the object from the managed environment's point of view?
For instance, did I create it, or was the object provided indirectly by another object I created?
Are there no further references to this object or its container in the managed environment?
Am I definitely not using the object after ReleaseComObject, in the code that follows it, or at any other time (e.g. by making sure not to store it in a field, or closure, even in the form of an iterator method or async method)?
This is to avoid the dreaded disconnected RCW exception.

Mono.CSharp: how do I inject a value/entity *into* a script?

Just came across the latest build of Mono.CSharp and love the promise it offers.
Was able to get the following all worked out:
namespace XAct.Spikes.Duo
{
class Program
{
static void Main(string[] args)
{
CompilerSettings compilerSettings = new CompilerSettings();
compilerSettings.LoadDefaultReferences = true;
Report report = new Report(new Mono.CSharp.ConsoleReportPrinter());
Mono.CSharp.Evaluator e;
e= new Evaluator(compilerSettings, report);
//IMPORTANT:This has to be put before you include references to any assemblies
//our you;ll get a stream of errors:
e.Run("using System;");
//IMPORTANT:You have to reference the assemblies your code references...
//...including this one:
e.Run("using XAct.Spikes.Duo;");
//Go crazy -- although that takes time:
//foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
//{
// e.ReferenceAssembly(assembly);
//}
//More appropriate in most cases:
e.ReferenceAssembly((typeof(A).Assembly));
//Exception due to no semicolon
//e.Run("var a = 1+3");
//Doesn't set anything:
//e.Run("a = 1+3;");
//Works:
//e.ReferenceAssembly(typeof(A).Assembly);
e.Run("var a = 1+3;");
e.Run("A x = new A{Name=\"Joe\"};");
var a = e.Evaluate("a;");
var x = e.Evaluate("x;");
//Not extremely useful:
string check = e.GetVars();
//Note that you have to type it:
Console.WriteLine(((A) x).Name);
e = new Evaluator(compilerSettings, report);
var b = e.Evaluate("a;");
}
}
public class A
{
public string Name { get; set; }
}
}
And that was fun...can create a variable in the script's scope, and export the value.
There's just one last thing to figure out... how can I get a value in (eg, a domain entity that I want to apply a Rule script on), without using a static (am thinking of using this in a web app)?
I've seen the use compiled delegates -- but that was for the previous version of Mono.CSharp, and it doesn't seem to work any longer.
Anybody have a suggestion on how to do this with the current version?
Thanks very much.
References:
* Injecting a variable into the Mono.CSharp.Evaluator (runtime compiling a LINQ query from string)
* http://naveensrinivasan.com/tag/mono/
I know it's almost 9 years later, but I think I found a viable solution to inject local variables. It is using a static variable but can still be used by multiple evaluators without collision.
You can use a static Dictionary<string, object> which holds the reference to be injected. Let's say we are doing all this from within our class CsharpConsole:
public class CsharpConsole {
public static Dictionary<string, object> InjectionRepository {get; set; } = new Dictionary<string, object>();
}
The idea is to temporarily place the value in there with a GUID as key so there won't be any conflict between multiple evaluator instances. To inject do this:
public void InjectLocal(string name, object value, string type=null) {
var id = Guid.NewGuid().ToString();
InjectionRepository[id] = value;
type = type ?? value.GetType().FullName;
// note for generic or nested types value.GetType().FullName won't return a compilable type string, so you have to set the type parameter manually
var success = _evaluator.Run($"var {name} = ({type})MyNamespace.CsharpConsole.InjectionRepository[\"{id}\"];");
// clean it up to avoid memory leak
InjectionRepository.Remove(id);
}
Also for accessing local variables there is a workaround using Reflection so you can have a nice [] accessor with get and set:
public object this[string variable]
{
get
{
FieldInfo fieldInfo = typeof(Evaluator).GetField("fields", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
var fields = fieldInfo.GetValue(_evaluator) as Dictionary<string, Tuple<FieldSpec, FieldInfo>>;
if (fields != null)
{
if (fields.TryGetValue(variable, out var tuple) && tuple != null)
{
var value = tuple.Item2.GetValue(_evaluator);
return value;
}
}
}
return null;
}
set
{
InjectLocal(variable, value);
}
}
Using this trick, you can even inject delegates and functions that your evaluated code can call from within the script. For instance, I inject a print function which my code can call to ouput something to the gui console window:
public delegate void PrintFunc(params object[] o);
public void puts(params object[] o)
{
// call the OnPrint event to redirect the output to gui console
if (OnPrint!=null)
OnPrint(string.Join("", o.Select(x => (x ?? "null").ToString() + "\n").ToArray()));
}
This puts function can now be easily injected like this:
InjectLocal("puts", (PrintFunc)puts, "CsInterpreter2.PrintFunc");
And just be called from within your scripts:
puts(new object[] { "hello", "world!" });
Note, there is also a native function print but it directly writes to STDOUT and redirecting individual output from multiple console windows is not possible.

How does Undo work?

How does undo work? Does it copy all the managed objects every time any of the values change? Or does it only copy the actual changes together with an information which objects were affected? Is that heavy or lightweight?
The 'undo' mechanism for pretty much any language that supports Object-Oriented constructs uses the Memento Design Pattern to make it happen.
Here's a rough implementation to get you thinking. This handles your stack of undoable operations. (It doesn't handle redo, but that's easy to support by replacing the stack with a list and keeping track of the current item.)
public class Undoable {
public static void Do(Action do, Action undo) {
do();
sUndoStack.Push(new Undoable(do, undo));
}
public static void Undo() {
sUndoStack.Pop().mUndoCallback();
}
private Undoable(Action doCallback, undoCallback) {
mDoCallback = doCallback;
mUndoCallback = undoCallback;
}
private Action mDoCallback, mUndoCallback;
// note: using a global stack here is lame, but works for demo purposes
private static readonly Stack<Undoable> sUndoStack = new Stack<Undoable>();
}
To use this, let's say the user can change a value in some object like this:
public class Foo {
public string Bar {
get { return mBar; }
set {
if (mBar != value) {
mBar = value;
}
}
}
private string mBar;
}
To make that operation undoable, we just change the setter to:
set {
if (mBar != value) {
string oldValue = mBar;
Undoable.Do(() => mBar = value,
() => mBar = oldValue);
}
}
Now, if you call Undoable.Undo() from anywhere in the application, your instance of Foo will restore the previous value of Bar. If Foo also raises an event when Bar changes (not shown here), the UI will also properly refresh on undo too.

How do i get the invoked operation name within a WCF Message Inspector

I'm doing a message inspector in WCF:
public class LogMessageInspector :
IDispatchMessageInspector, IClientMessageInspector
which implements the method:
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
I can get the name of the invoked service with:
instanceContext.GetServiceInstance().GetType().Name
But how do I get the name of the invoked operation?
It's not pretty, but this is what I did to get the operation name:
var action = OperationContext.Current.IncomingMessageHeaders.Action;
var operationName = action.Substring(action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1);
var operationName = OperationContext.Current.IncomingMessageProperties["HttpOperationName"] as string;
This approach is similar to others presented here, but uses Path.GetFileName:
Path.GetFileName(OperationContext.Current.IncomingMessageHeaders.Action);
The return value of this method and the format of the path string work quite harmoniously in this scenario:
The characters after the last directory character in path. If the last
character of path is a directory or volume separator character, this
method returns String.Empty. If path is null, this method returns
null.
OperationContext.Current.IncomingMessageHeaders.Action.Split('/').ToList().Last();
Little late to the party but I had to dig a little deeper than existing answers on this question because they seem to involve getting the action name and not the operation name. (Frequently they are the same so getting the action name does, in fact, get the operation name.)
Microsoft's Application Insights SDK Labs' WCF library makes this concerted effort:
private string DiscoverOperationName(OperationContext operationContext)
{
var runtime = operationContext.EndpointDispatcher.DispatchRuntime;
string action = operationContext.IncomingMessageHeaders.Action;
if (!string.IsNullOrEmpty(action))
{
foreach (var op in runtime.Operations)
{
if (op.Action == action)
{
return op.Name;
}
}
}
else
{
// WebHttpDispatchOperationSelector will stick the
// selected operation name into a message property
return this.GetWebHttpOperationName(operationContext);
}
var catchAll = runtime.UnhandledDispatchOperation;
if (catchAll != null)
{
return catchAll.Name;
}
return "*";
}
private string GetWebHttpOperationName(OperationContext operationContext)
{
var name = WebHttpDispatchOperationSelector.HttpOperationNamePropertyName;
if (this.HasIncomingMessageProperty(name))
{
return this.GetIncomingMessageProperty(name) as string;
}
return "<unknown>";
}