set filepath from database in SSIS variable for logging - c#

I have some paths in my database table like this:
ID PATHXML PATHPICT PATHSONG
1 D:\XML\Here D:\Picture\Image D:\Blur\Song2
2 D:\XML\File D:\Picture\X-Files D:\IRONMAIDEN\Fearofthedark
I want to switch on logging in SSIS and save this log result to PathSong eg. D:\Blur\Song2\eventlog.log
I created a variable to get this path. But when I create an expression using this variable, it doesn't work. So what can I do to fix this?

Accessing package variables in a Script Component (of a Data Flow Task) is not the same as accessing package variables in a Script Task. For a Script Component, you first need to open the Script Transformation Editor (right-click on the component and select "Edit..."). In the Custom Properties section of the Script tab, you can enter (or select) the properties you want to make available to the script, either on a read-only or read-write basis:
Then, within the script itself, the variables will be available as strongly-typed properties of the Variables object:
// Modify as necessary
public override void PreExecute()
{
base.PreExecute();
string thePath = Variables.FilePath;
// Do something ...
}
public override void PostExecute()
{
base.PostExecute();
string theNewValue = "";
// Do something to figure out the new value...
Variables.FilePath = theNewValue;
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
string thePath = Variables.FilePath;
// Do whatever needs doing here ...
}
One important caveat: if you need to write to a package variable, you can only do so in the PostExecute() method.
Regarding the code snippet:
IDTSVariables100 varCollection = null;
this.VariableDispenser.LockForRead("User::FilePath");
string XlsFile;
XlsFile = varCollection["User::FilePath"].Value.ToString();
varCollection is initialized to null and never set to a valid value. Thus, any attempt to dereference it will fail.

Related

Blazor - How to Call Independent JSInterop Methods Located on Layout and Child Components

Up until the day before this post was first made, I have been calling JSInvokable methods just fine from any page loaded in the app. I was creating and establishing the the DotNotObjectReference objects as traditionally shown in most examples like so:
var dotNetReference = DotNetObjectReference.Create(this);
JSRuntime.InvokeVoidAsync("SetDotNetObjectRef", dotNetReference);
In the individual pages themselves, I would create the invokable methods like so:
#page "/Application/Search/Index/"
#code {
[JSInvokable]
public void InvokableMethodOnIndexPage(string id)
{
return;
}
protected override void OnAfterRender(bool isFirstRender)
{
if (isFirstRender)
{
var dotNetReference = DotNetObjectReference.Create(this);
JSRuntime.InvokeVoidAsync("SetDotNetObjectRef", dotNetReference);
}
}
}
Then, I needed to build a new JSInvokable method that was to be re-used on any page in the app, and so I placed that method in my "MainLayout.razor" component that all of my pages derive the design layout from like so:
#code {
[JSInvokable]
public void InvokableMethodOnMainLayout(string id)
{
return;
}
protected override void OnAfterRender(bool isFirstRender)
{
if (isFirstRender)
{
var dotNetReference = DotNetObjectReference.Create(this);
JSRuntime.InvokeVoidAsync("SetDotNetObjectRef", dotNetReference);
}
}
}
In my first attempts to call the new function that I placed in the "MainLayout.razor" file, I was getting the "The type 'Index' does not contain a public invokable method with [JSInvokableAttribute('InvokableMethodOnMainLayout')].".
Through my research and testing, I discovered that both of the DotNetObjectReference.Create(this) lines in each file were clashing with each other with child instance overriding the "MainLayout" DotNetObjectReference instance. When I removed the child instance reference, the call to the method in MainLayout would execute fine but then in turn, it broke the ability to the call the InvokableMethodOnIndexPage(string id) method.
My first thought was to alter the _Host view file to maintain an array of references and then build a helper function that would loop through the references and try/catch each reference until it hit a reference that it could find the function I wanted to call but I decided that may not be the best approach and/or would be expensive operation.
Therefore, may I ask what the appropriate implementation here to provide the functionality to call JSInvokable methods from any component?
Regards.
So, after having a revelation and giving this some more thought, I tested a different way to address the original clashing of DotNetObjectReference between parent and child Blazor components and came up with the following code to address the issue at hand.
The first thing was to redo/create JavaScript helper functions inside of the _Host file to resemble the following:
window.DotNetObjectRefs = [];
window.SetDotNetObjectRef = function (dotNetObjectRef, componentName) {
if(window.DotNetObjectRefs.filter(dnor => return dnor.ComponentName === componentName).length <= 0)
{
window.DotNetObjectRefs.push({ ComponentName: componentName, Reference: dotNetObjectRef });
}
};
window.InvokeMethodAsync = function (assembly, componentName, method, args) {
for(let r = 0; r < window.DotNetObjectRefs.length; r++)
{
if (window.DotNetObjectRefs[r].ComponentName === componentName)
{
window.DotNetObjectRefs[r].Reference.invokeMethodAsync(method, args);
}
}
};
The key change to this was to hold an array of references that don't clash with each other. By creating an array to hold references, you can create multiple references and add them with a naming convention that refers to the component the reference was instantiated from. Then, when you need to call an invokable function, you just specify the component the invokable method comes from in addition to the method name and arguments.
Then, in any component that requires JSInterop capabilities, this:
JSRuntime.InvokeVoidAsync("SetDotNetObjectRef", DotNetObjectReference.Create(this));
becomes this:
JSRuntime.InvokeVoidAsync("SetDotNetObjectRef", DotNetObjectReference.Create(this), "Reference_Component_Name");
This will now allow you to define JSInvokable methods on any component and have them be called from any other component as long as you reference the component name in the Invoke calls.

Roslyn analyser - check for null references for a specific type

I am checking for the possibility to build custom roslyn analyzer for case specifics to our system.
The solution is in .net Framework 4.8. I started with the tutorial How to write csharp analyzer code fix and am making my way from there.
The first case I want to check is that when the programmer use the value of a specific service they must not assume that the result is not null.
Take this service definition :
public interface IConfigurationService
{
Task<IConfiguration> GetConfiguration(string clientId);
}
And a code sample to analyze :
public async Task DoSomeTask(string clientId)
{
var configuration = await _configurationService.GetConfiguration(clientId);
// This line should raise a warning because this specific client may not be configurated
var serviceUri = configuration.ServiceUri;
DoSomeSubTask(serviceUri);
}
So far I got this
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
// The goal is to target the variable declaration (var configuration = ...)
context.RegisterSyntaxNodeAction(
AnalyzeDecalaration,
SyntaxKind.LocalDeclarationStatement
);
}
private static void AnalyzeDecalaration(SyntaxNodeAnalysisContext context)
{
// Check for the type of the variable and exit if it is not 'IConfiguration'
var symbolInfo = context.SemanticModel.GetSymbolInfo(localDeclaration.Declaration.Type);
var typeSymbol = symbolInfo.Symbol;
if (typeSymbol.Name != "IConfiguration")
{
return;
}
// Stuck here. I'm pretty sure dataFlowAnalysis is the key, but I can't figure how to use it
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(localDeclaration);
var variable = localDeclaration.Declaration.Variables.Single();
ISymbol variableSymbol = context.SemanticModel.GetDeclaredSymbol(
variable,
context.CancellationToken
);
}
So that's where I am. I have targeted variable declaration for the target type. Not very much.
Since it is a specific case for a specific type, the analysis does not have to be very fancy. For exemple, I don't need to check for instanaces of IConfiguration inside an array, that's not a thing in our code base. Basically juste property access without null check.

Implementing "Intellisense" for IronPython

In my C# application I have a text editor that allows the user to enter IronPython scripts. I have implemented a set of C# classes that are made available to the python environment.
I would now like to implement an "intellisense" type of system where the user enters a variable name then a dot and it prompts the user for a list of available methods and properties.
For example here is an IronPython script:
foo = MyClass()
foo.
At this point the cursor is just after the dot. MyClass example in C#:
public class MyClass {
public void Func1() ...
public void Func2() ...
}
Now I would like to give the user a pop up list showing Func1(), Func2(), etc.
What I need to do is take the variable name "foo" and get the class MyClass.
Note that I can't execute the IronPython code to do this because it performs actions in the user interface.
This is how far I have been able to get:
ScriptSource Source = engine.CreateScriptSourceFromString(pycode, SourceCodeKind.File);
SourceUnit su = HostingHelpers.GetSourceUnit(Source);
Microsoft.Scripting.Runtime.CompilerContext Ctxt = new Microsoft.Scripting.Runtime.CompilerContext(su, new IronPython.Compiler.PythonCompilerOptions(), ErrorSink.Null);
IronPython.Compiler.Parser Parser = IronPython.Compiler.Parser.CreateParser(Ctxt, new IronPython.PythonOptions());
IronPython.Compiler.Ast.PythonAst ast = Parser.ParseFile(false);
if (ast.Body is IronPython.Compiler.Ast.SuiteStatement)
{
IronPython.Compiler.Ast.SuiteStatement ss = ast.Body as IronPython.Compiler.Ast.SuiteStatement;
foreach (IronPython.Compiler.Ast.Statement s in ss.Statements)
{
if (s is IronPython.Compiler.Ast.ExpressionStatement)
{
IronPython.Compiler.Ast.ExpressionStatement es = s as IronPython.Compiler.Ast.ExpressionStatement;
}
}
}
I can see that the last line of the script foo. is an ExpressionStatement and I can drill down from there to get the NameExpression of 'foo' but I can't see how to get the type of the variable.
Is there a better way to do this? Is it even possible?
Thanks!

Accesing script scope variables from modules

We use IronPython in our open source project. I have problem accesing the variables added to the script scope like
private ScriptScope CreateScope(IDictionary<string, object> globals)
{
globals.Add("starting", true);
globals.Add("stopping", false);
var scope = Engine.CreateScope(globals);
scope.ImportModule("math");
return scope;
}
https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptEngine.cs#L267
I can use the globals from the main script, but any module that is loaded will fail. How can it be fixed?
update: Given this module mymodule.py
if starting: #starting is defined on the scope
...
From the main script executed using this code
void RunLoop(string script, ScriptScope scope)
{
ExecuteSafe(() =>
{
var compiled = Engine.CreateScriptSourceFromString(script).Compile();
while (!stopRequested)
{
usedPlugins.ForEach(p => p.DoBeforeNextExecute());
CatchThreadAbortedException(() => compiled.Execute(scope));
scope.SetVariable("starting", false);
threadTimingFactory.Get().Wait();
}
scope.SetVariable("stopping", true);
CatchThreadAbortedException(() => compiled.Execute(scope));
});
}
https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptEngine.cs#L163
from mymodule import * #this will load the moduel and it fails with
edit: In response to #BendEg's answer
I tried this
scope.SetVariable("__import__", new Func<CodeContext, string, PythonDictionary, PythonDictionary, PythonTuple, object>(ResolveImport));
ImportDelegate is not defined so tried using a Func instead, the ResolveImport method never triggers and I get the same exception that the name is not defined
edit: I changed the scope creation to
var scope = Engine.GetBuiltinModule();
globals.ForEach(g => scope.SetVariable(g.Key, g.Value));
Now the import delegate triggers but it crashes on first line with global name 'mouse' is not defined, mouse is not used from the module. It seems its confused when I add my custom globals to the BuiltinModule
This is probably not the right answer, as still doesn't allow to share variables defined in the main IronPhyton script with the imported modules, however is a step forward.
This approach allows to set variables at the Engine level rather then the script level and they will be available in every imported module.
engine = Python.CreateEngine();
engine.Runtime.Globals.SetVariable("test_global", "This is a test global variable.");
then, within any IronPhyton script is possible to access it using an import:
import test_global
print(test_global)
Unlike ScriptScope, which makes them directly available, those Global variables need to be imported.
Original article
https://ludovic.chabant.com/devblog/2009/12/24/exposing-global-variables-in-ironpython/
Disclaimer
I added this answer as I've been struggling to find any material on this topic other then this SO Q&A, so I'm posting this possible workaround to help future troubled readers (like myself)
As far as i know, importing some module will create a new scope. So when creating an instance of PythonModule via from ... import ... they has it's own scope. In this new scope, your public variables are not available. Please correct me if i am wrong.
Workaround:
You could create some static class, which holdes the values. Than you can be sure, you always have them. For example:
namespace someNS
{
public static class SomeClass
{
public static bool Start { get; set; }
}
}
And than in your IP-Code:
from someNS import SomeClass
# Now you can access the member
yourVal = SomeClass.Start
maybe this is some thing you can use. You event don't need to set it as variable in the scope.
EDIT
Maybe this is working for you. In the code i override module importing and try to set the global vars:
First thing you need is, give IronPython some delegate, for module importing:
# Scope should be your default scope
scope.SetVariable("__import__", new ImportDelegate(ResolveImport));
Then override the import function:
private object ResolveImport(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist)
{
// Do default import but set module
var builtin = IronPython.Modules.Builtin.__import__(context, moduleName, globals, locals, fromlist, 0);
context.ModuleContext.Module.__setattr__(context, "some_global", "Hello World");
return builtin;
}
EDIT
Definition of ImportDelegate
delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist);

How to get all visible local variable names within a scope with Roslyn (Microsoft CodeAnalysis)

(Please note: This is not about run-time reflection/metainfo)
I am writing a concrete implementation of Roslyn CSharpSyntaxVisitor
When implementing the VisitIdentifierName
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax name)
{
var symbolInfo = _semanticModel.GetSymbolInfo(name);
var fieldSymbol = symbolInfo.Symbol as IFieldSymbol;
if (fieldSymbol != null)
{
// Here I would like to get all the local variable names what are visible
// in the very same scope where this field IdentifierNameSyntax under visiting resides
// We can suppose that _semanticNodel for the Document is available.
}
}
Call SemanticModel.LookupSymbols() (source), then filter for local variables.
You may also want to filter out locals declared after that location; see this code.

Categories