Why Can't I call this method? - c#

I'm trying to call a method from another class within a service, however it's saying that the method I'm trying to call doesn't exist and would like some help if possible.
the program is a work project, which logs user inactivity as we've had issues with people not picking up the phone, code is below, this is a topshelf service that consumes messages from rabbitMQ and I want it to consume the messages and forward them to a database =]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using NLog;
using IWshRuntimeLibrary;
using Topshelf;
using System.Data.Odbc;
using EasyNetQ;
using RabbitMQ;
using EasyNetQ.Topology;
using System.Threading.Tasks;
using System.Windows.Forms;
using AccessEye;
namespace LogService
{
public class WindowsServiceHost : ServiceControl, ServiceShutdown
{
public static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public bool Start(HostControl hostControl)
{
Program.bus = RabbitHutch.CreateBus("host=as01.access.local;virtualHost=DEV-Reece;username=reece;password=reece").Advanced;
//var bus = RabbitHutch.CreateBus("host=as01.access.local;virtualHost=DEV-Reece;username=reece;password=reece").Advanced;
var queue = Queue.Declare(true, false, true, null);
var exchange = Exchange.DeclareFanout("UserActivityFanout", true, false, null);
var exchangeTopic = Exchange.DeclareTopic("UserActivity", true, false, null);
queue.BindTo(exchange, "#");
exchange.BindTo(exchangeTopic, "#");
Program.bus.Subscribe<AccessEye.LogData>(queue, (msg, messageRecInfo) => Task.Factory.StartNew(() =>
{
WriteLogDataToDb();
Console.WriteLine(msg.Body.UserName + " -- " + msg.Body.ComputerName + " -- " + msg.Body.EventType + " -- " + msg.Body.TeamviewerId);
}));
return true;
}
And this is the method I'm trying to call
public partial class AppForm : Form
{
public static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private Screensaver watcher;
public Inactivity inactivity;
IAdvancedBus bus;
IExchange exchange;
public void WriteLogDataToDb(LogData data)
{
using (var db = new LogService.UserActivityDataContext())
{
DbLogData logData = AutoMapper.Mapper.Map<LogData, DbLogData>(data);
int t = (int)data.EventType;
EventType eventType = db.EventTypes.FirstOrDefault(r => r.Id == t);
if (eventType == null)
{
eventType = db.EventTypes.Add(new EventType
{
Event = GetEnumDescriptionAttributeValue(data.EventType),
Id = (int)data.EventType
});
db.SaveChanges();
}
logData.EventTypeId = eventType.Id;
db.LogEvents.Add(logData);
db.SaveChanges();
}
}

If your class with the WriteLogDataToDb() declared is called ClassA, then do two things. Make the method static, and you actually have to pass some LogData data through it.
public class AppForm
{
public static void WriteLogDataToDb(LogData data)
{
using (var db = new LogService.UserActivityDataContext())
{
DbLogData logData = AutoMapper.Mapper.Map<LogData, DbLogData>(data);
int t = (int)data.EventType;
EventType eventType = db.EventTypes.FirstOrDefault(r => r.Id == t);
if (eventType == null)
{
eventType = db.EventTypes.Add(new EventType
{
Event = GetEnumDescriptionAttributeValue(data.EventType),
Id = (int)data.EventType
});
db.SaveChanges();
}
logData.EventTypeId = eventType.Id;
db.LogEvents.Add(logData);
db.SaveChanges();
}
}
}
Then in your Start code, you have to call AppForm.WriteLogDataToDb(data)
Edit:
Now that these classes are in two different projects, you need to add reference so your WindowsServiceHost can use AppForm. To do this:
Right-click > Properties on the project containing AppForm. On the Application tab, take note of the Assembly name:
Right-click the References item in WindowsServiceHost and choose Add reference
Go to the Projects tab
Add the Assembly name: noted in step #1
Right click AppForm in WindowsSerivceHost and Resolve by adding your using statement.

Related

Neo4j assembly error when running through Revit software

I am building an addin for Autodesk's Revit.
I created a class library .NET Framework project called neo4jTest.
I'm trying to use the Neo4j API to communicate with the DB and save data to it.
I try to following:
Compile the .dll, and place the .dll file and .addin file in the
Revit folder which can load it.
Start Revit, and click "Load Once" for the addin approval.
Click the Button I've created (in the appropriate Tab)
Error appears (image below)
Run the .dll directly from the add-in manager -> no error.
Click the Button again -> no error.
I am expecting:
No error, and that both the direct execution of the .dll, and the Button, to perform the same action.
Neo4j DB logs the data being sent. Currently I can't see the data is actually being updated.
Is Revit first loading the assembly locally or caching it in some way when I run the .dll directly and then the loaded addin can use it because it is available?
Would appreciate any advice on how to go around this or solve it.
Thank you
CODE:
Main.cs file for button creation:
using Autodesk.Revit.UI;
using System.Reflection;
namespace neo4jTest
{
public partial class Main : IExternalApplication
{
public UIControlledApplication _application;
public Result OnStartup(UIControlledApplication application)
{
_application = application;
string tabName = "Neo4jTest";
application.CreateRibbonTab(tabName);
RibbonPanel ribbonPanel = application.CreateRibbonPanel(tabName, "Neo4jTest");
string thisAssemblyPath = Assembly.GetExecutingAssembly().Location;
InitializeButtons(ribbonPanel, thisAssemblyPath);
return Result.Succeeded;
}
private void InitializeButtons(RibbonPanel ribbonPanel, string thisAssemblyPath)
{
CreateButton(ribbonPanel, "neo4jTest", "neo4jTest", thisAssemblyPath, "neo4jTest.Class1", "neo4jTest");
}
public Result OnShutdown(UIControlledApplication application)
{
return Result.Succeeded;
}
private void CreateButton(
RibbonPanel ribbonPanel,
string name,
string text,
string thisAssemblyPath,
string className,
string toolTip
)
{
PushButtonData buttonData = new PushButtonData(name, text, thisAssemblyPath, className);
PushButton pushButton = ribbonPanel.AddItem(buttonData) as PushButton;
pushButton.ToolTip = toolTip;
}
}
}
Neo4jConnection.cs for establishing DB data:
using Autodesk.Revit.UI;
using Neo4j.Driver;
using System;
using System.Threading;
namespace neo4jTest
{
public static class Neo4jConnection
{
public static IDriver _driver;
private static readonly string uri = "myUri";
private static readonly string user = "myUser";
private static readonly string password = "myPassword";
public static void SaveToDB()
{
try
{
_driver = GraphDatabase.Driver(uri, AuthTokens.Basic(user, password));
var session = _driver.AsyncSession();
var data = session.ExecuteWriteAsync(async tx =>
{
var result = await tx.RunAsync("CREATE (n:Testing) " +
"SET n.fulltext = testing text " +
"SET n.username = userTest " +
"RETURN n"
);
return await result.ToListAsync();
});
Thread.Sleep(500);
session.Dispose();
}
catch (Exception ex)
{
TaskDialog.Show("Error", ex.StackTrace);
}
}
}
}
Class1 for executing button:
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
namespace neo4jTest
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class Class1 : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
Neo4jConnection.SaveToDB();
TaskDialog.Show("Validate", "Done");
return Result.Succeeded;
}
}
}

ActivitySource.StartActivity returns null as if there is no listeners even though console listener is defined

The code uses Console Trace Provider. However, In the function static void MakeActivity(string name),
The line ActivitySource.startActivity returns a null. How can i fix it?
The examples on google have the "using" keyword which i cannot apply with .net 4.7 with which my project id bound against.
/// <summary>
/// Starts up the OpenTelemetry and JeagerTracing connection
/// </summary>
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnitTestProject1
{
class Program
{
private static ResourceBuilder BackendServiceResource { get; set; }
private static readonly ActivitySource ActivitySource = new ActivitySource("Sample.DistributedTracing");
private static readonly string serveradress = "127.0.0.1";
private static readonly int serverPort = 6831;
public static TracerProvider Provider { get; set; }
public static Tracer OpenTelemetryTracer { get; set; }
static void Main(string[] args)
{
var serviceName = "MyCompany.MyProduct.MyService";
var serviceVersion = "1.0.0";
Provider = GetConsoleTraceProvider(serviceName, serviceVersion);
OpenTelemetryTracer = Provider.GetTracer(ActivitySource.Name);
MakeActivity("Test 1");
MakeActivity("Test 2");
MakeActivity("Test 3");
MakeActivity("Test 4");
MakeActivity("Test 5");
}
static void MakeActivity(string name)
{
Activity activity = ActivitySource.StartActivity(name); // this returns null even though i have a trace provider setup using GetConsoleTraceProvider
activity.AddTag("machine.name", Environment.MachineName);
activity.AddTag("user.name", Environment.UserName);
Task.Delay(5000);
activity.Stop();
}
public static TracerProvider GetConsoleTraceProvider(string serviceName,string serviceVersion)
{
// Configure important OpenTelemetry settings and the console exporter
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(serviceName)
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService(serviceName: serviceName, serviceVersion: serviceVersion))
.AddConsoleExporter()
.Build();
return tracerProvider;
}
}
}
vs this code sample works as i am using a c# 10 feature.
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;
using OpenTelemetry.Exporter;
// Define some important constants and the activity source
var serviceName = "MyCompany.MyProduct.MyService";
var serviceVersion = "1.0.0";
// Configure important OpenTelemetry settings and the console exporter
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(serviceName)
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService(serviceName: serviceName, serviceVersion: serviceVersion))
.AddConsoleExporter()
.Build();
var MyActivitySource = new ActivitySource(serviceName);
using var activity = MyActivitySource.StartActivity("SayHello");
activity?.SetTag("foo", 1);
activity?.SetTag("bar", "Hello, World!");
activity?.SetTag("baz", new int[] { 1, 2, 3 });

SQLCLR Trigger/Procedure in LocalDB?

I'm trying to get SQL CLR procedures working with LocalDB (2012). My trigger and procedure (below) are never called. I'm creating the LocalDB with Entity Framework 6. Is the trigger supposed to work in this scenario?
using System;
using System.Data;
using System.Data.Entity;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Dapper;
namespace TestSqlCallback
{
class Program
{
public class MyEntity
{
public long Id { get; set; }
public string Value { get; set; }
}
public class MyContext: DbContext
{
static MyContext()
{
AppDomain.CurrentDomain.SetData("DataDirectory", Path.GetTempPath());
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
}
public DbSet<MyEntity> Entities { get; set; }
}
static void Main(string[] args)
{
var context = new MyContext();
var count = context.Entities.Count();
Console.WriteLine("Starting with {0} entities.", count);
var con = context.Database.Connection;
con.Execute("sp_configure 'clr enabled', 1;");
con.Execute("reconfigure");
con.Execute("CREATE ASSEMBLY [TestSqlCallbackTriggers] from '" + typeof(Triggers.MySqlClr).Assembly.Location + "';");
con.Execute(#"CREATE TRIGGER TestTrigger ON [dbo].[MyEntities] FOR INSERT, UPDATE, DELETE
AS EXTERNAL NAME TestSqlCallbackTriggers.[TestSqlCallback.Triggers.MySqlClr].TestTrigger;");
con.Execute(#"CREATE PROCEDURE TestProcedure AS EXTERNAL NAME TestSqlCallbackTriggers.[TestSqlCallback.Triggers.MySqlClr].TestProcedure;");
context.Entities.Add(new MyEntity {Value = "be cool"});
var sw = Stopwatch.StartNew();
con.Execute("TestProcedure", commandType: CommandType.StoredProcedure);
context.SaveChanges();
count = context.Entities.Count();
Console.WriteLine("Ending with {0} entities. Waiting for trigger...", count);
SpinWait.SpinUntil(() => Triggers.MySqlClr.Workaround.Value > 1);
Console.WriteLine("Finised in {0}ms", sw.Elapsed.TotalMilliseconds);
if (Debugger.IsAttached)
Console.ReadKey();
}
}
}
Other file in other project with fewer dependencies:
using System.Threading;
using Microsoft.SqlServer.Server;
namespace TestSqlCallback.Triggers
{
public class MySqlClr
{
public class Wrapper<T>
{
public T Value;
}
public readonly static Wrapper<int> Workaround = new Wrapper<int>();
//[SqlTrigger(Name = "TestTrigger", Event = "FOR INSERT, UPDATE, DELETE", Target = "[dbo].[MyEntities]")]
//[SqlTrigger] // doesn't work with or without
public static void TestTrigger()
{
var context = SqlContext.TriggerContext;
if (context == null) return;
switch (context.TriggerAction)
{
case TriggerAction.Insert:
Interlocked.Increment(ref Workaround.Value);
break;
case TriggerAction.Update:
break;
case TriggerAction.Delete:
break;
default:
return;
}
}
//[SqlProcedure]
public static void TestProcedure()
{
var context = SqlContext.TriggerContext;
if (context == null) return;
Interlocked.Increment(ref Workaround.Value);
}
}
}
I tried the same thing and eventually just used a SqlDataReader. Regardless, I needed to put the correct connection string in my app.config file.
The reference looked like this:
<connectionStrings>
<add name="MyAwesomeDBEntities" connectionString="metadata=res://*/MyAwesomeDBLocalDB.csdl|res://*/MyAwesomeDBLocalDB.ssdl|res://*/MyAwesomeDBLocalDB.msl;provider=System.Data.SqlClient;provider connection string="data source=np:\\.\pipe\LOCALDB#C1AA2FB7\tsql\query;initial catalog=MyAwesomeDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
For this to work, I needed to update the data source part of the connection string after starting the database from the command line.
I ran "sqllocaldb.exe info" in a command prompt to get the instance names. In my case, I ran "sqllocaldb.exe info v11.0" (after running "sqllocaldb.exe start v11.0") and compared the "Instance pipe name" value to the "data source" part of the connection string.
If this still doesn't work, then I'll update my answer to provide more information.

Debugging Data-Service-Request-Exception on WCF-Data-Service during add new entity

this is my service code :
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.Web;
namespace RadAppSilver.Web
{
public class DsWFS006 : DataService<WFS006Entities>
{
public DsWFS006()
{
ServiceHost host = new ServiceHost(typeof(DsWFS006));
ServiceDebugBehavior debug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
// if not found - add behavior with setting turned on
if (debug == null)
{
host.Description.Behaviors.Add(
new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
// make sure setting is turned ON
if (!debug.IncludeExceptionDetailInFaults)
{
debug.IncludeExceptionDetailInFaults = true;
}
}
host.Open();
// This method is called only once to initialize service-wide policies.
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
//config.SetEntitySetPageSize("DocDetail", 30);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
}
I need to debug when I'm going to new record to my entity error happened but update entity works fine :
private void Grid1RowEditEnded(object sender, Telerik.Windows.Controls.GridViewRowEditEndedEventArgs e)
{
if (e.EditAction == Telerik.Windows.Controls.GridView.GridViewEditAction.Commit)
{
doc.AccNo = string.IsNullOrEmpty(SelectedAcc) ? doc.AccNo : SelectedAcc;
if (e.EditOperationType == Telerik.Windows.Controls.GridView.GridViewEditOperationType.Edit)
{
service.UpdateObject(doc);
}
else if (e.EditOperationType == Telerik.Windows.Controls.GridView.GridViewEditOperationType.Insert)
{
(this.grid1.ItemsSource as VirtualQueryableCollectionView).Add(doc);
service.AddObject("DocDetail", doc);
}
service.BeginSaveChanges(OnChangesSaved, service);
}
}
private void OnChangesSaved(IAsyncResult result)
{
Dispatcher.BeginInvoke(() =>
{
service = result.AsyncState as DS1.WFS006Entities;
try
{
service.EndSaveChanges(result);
}
catch (DataServiceRequestException ex)
{
MessageBox.Show(ex.Response.ToString());
}
catch (InvalidOperationException ex)
{
MessageBox.Show(ex.Message);
}
});
}
and this code include initializing service on my client :
private void SetContext()
{
service = new DSEntity();
DataServiceQuery<DS1.Accounts> queryAcc = (DataServiceQuery<DS1.Accounts>)
(service.Accounts.Select(m =>
new DS1.Accounts
{
AccNo = m.AccNo,
AccDesc = m.AccDesc
}));
queryAcc.BeginExecute(t =>
{
DataServiceQuery<DS1.Accounts> state = t.AsyncState as DataServiceQuery<DS1.Accounts>;
var executedState = state.EndExecute(t);
ObservableCollection<DS1.Accounts> data = new ObservableCollection<DS1.Accounts>();
foreach (var entity in executedState)
data.Add(entity);
AccCache = data.ToList();
}, queryAcc);
var view = new VirtualQueryableCollectionView() { LoadSize = 300, VirtualItemCount = 10000 };
view.ItemsLoading += (y, e) =>
{
DataServiceQuery<DS1.DocDetail> query = (DataServiceQuery<DS1.DocDetail>)
service.DocDetail.OrderBy(it => it.Item)
.Where<DS1.DocDetail>(it => it.DocSerNo == 91120001)
.Where(view.FilterDescriptors)
.Sort(view.SortDescriptors)
.Skip(e.StartIndex)
.Take(e.ItemCount);
query = query.IncludeTotalCount();
query.BeginExecute(
s =>
{
DataServiceQuery<DS1.DocDetail> state = s.AsyncState as DataServiceQuery<DS1.DocDetail>;
var executedState = state.EndExecute(s);
var response = executedState as QueryOperationResponse<DS1.DocDetail>;
int count = (int)response.TotalCount;
ObservableCollection<DS1.DocDetail> data = new ObservableCollection<DS1.DocDetail>();
foreach (var entity in executedState)
data.Add(entity);
var dataSource = data.ToList();
view.VirtualItemCount = count;
view.Load(e.StartIndex, dataSource);
}, query);
};
grid1.ItemsSource = view;
}
it doesn't work while add new object and exception doesn't give me any detail when I add host.open(); on constructor to show exception detail the service has been stop.
Include all the option for debugging the wcf service
1.Apply the following attribute to your service class
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
Override the following two methods in your service class
a. protected override void OnStartProcessingRequest(ProcessRequestArgs args)
b,protected override void HandleException(HandleExceptionArgs args)
set the break points on these two methods and see what type of exception.

C# script accessing previously compiled methods

I'm looking to move a scripting solution that I currently have over to C# as I believe as this will solve some of the issues which I am currently facing when it comes to running on different platforms. I can call functions which are within the script and access their variables, however, one thing that I would like to be able to do is call a function from the class that the script resides in. Does anyone know how I would be able to do this?
Here is my code at the minute which is working for calling and access objects within the script, but I would like to be able to call the method "Called" from within the script, but cannot:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.CSharp;
namespace scriptingTest
{
class MainClass
{
public static void Main (string[] args)
{
var csc = new CSharpCodeProvider ();
var res = csc.CompileAssemblyFromSource (
new CompilerParameters ()
{
GenerateInMemory = true
},
#"using System;
public class TestClass
{
public int testvar = 5;
public string Execute()
{
return ""Executed."";
}
}"
);
if (res.Errors.Count == 0) {
var type = res.CompiledAssembly.GetType ("TestClass");
var obj = Activator.CreateInstance (type);
var output = type.GetMethod ("Execute").Invoke (obj, new object[] { });
Console.WriteLine (output.ToString ());
FieldInfo test = type.GetField ("testvar");
Console.WriteLine (type.GetField ("testvar").GetValue (obj));
} else {
foreach (var error in res.Errors)
Console.WriteLine(error.ToString());
}
Console.ReadLine ();
}
static void Called() // This is what I would like to be able to call
{
Console.WriteLine("Called from script.");
}
}
}
I am attempting to do this in Mono, however, I don't believe this should affect how this would be resolved.
There are a handful of things you need to change.
MainClass and Called need to be accessible to other assemblies so make them public. Additionally, you need to add a reference to the current assembly to be able to access it in your script code. So essentially your code will end up looking like:
public class MainClass
public static void Called()
var csc = new CSharpCodeProvider();
var ca = Assembly.GetExecutingAssembly();
var cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("mscorlib.dll");
cp.ReferencedAssemblies.Add(ca.Location);
var res = csc.CompileAssemblyFromSource(
cp,
#"using System;
public class TestClass
{
public int testvar = 5;
public string Execute()
{
scriptingTest.MainClass.Called();
return ""Executed."";
}
}"
);
The output of running the test looks like:
Called from script.
Executed.
5

Categories

Resources