How to resolve dependency issues with C# script csx file in visual studio code? - visual-studio-code

I am trying to create an azure function program with a service bus queue trigger template using a csx file. But I am having issues resolving dependencies. To be honest, i am very confused about the project structure that is mentioned in [this doc] (https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp). I've tried two approaches.
First approach...
Create a folder named MyAzureFunc in a visual studio code and manually add a function.json , project.json, project.lock.json, and run.csx. Then, outside of the MyAzureFunc folder I add a host.json and local.settings.json. This approach leads to dependency issues.
Second approach...
Create an Azure Function project with service bus queue template in visual studio code that generates a completely different folder and project structure. I'll then remove most of the auto-generated files and manually add in the structure mentioned in the first approach. This still leads to dependency issues.
Some possible reasons i believe this could be happening is the following...
1. Framework versions - my project.json calls for "net46", but when i create an azure function in visual studio code using the service bus queue template it implements "netcoreapp2.1"
2. The need to run some command to recognize the package dependencies
3. Some project configuration needed to work with csx
I believe the important file here is the project.json. Below is the code...
{
"frameworks": {
"net46":{
"dependencies": {
"MongoDB.Driver": "2.6.1",
"MongoDB.Driver.Core": "2.6.1",
"MongoDB.Bson": "2.6.1",
"SharpZipLib": "0.86.0",
"RabbitMQ.CLient": "5.0.1"
}
}
}
}
Below is the code for the packages i'm trying to use in my csx file...
#r "Newtonsoft.Json"
#r "Microsoft.ServiceBus"
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ServiceBus.Messaging; --> ERROR
using Newtonsoft.Json; --> ERROR
using MongoDB.Driver; --> ERROR
using MongoDB.Bson; --> ERROR
using MongoDB.Bson.IO; --> ERROR
using RabbitMQ.Client; --> ERROR
using ICSharpCode.SharpZipLib.Zip.Compression.Streams; --> ERROR

Related

Azure Functions: Can compile but cannot run with custom datalayer library

I've tried to come up with a better title but can't.
The issue is I am new to Azure functions but have made a simple one work that writes to a SQL Azure table. Now I've attempted to build the simplest kind of Entity Framework based Datalayer and uploaded it. Right now it is compiled as .Net 4.6 and using EF 6.1.3.
I'm using a connection string as per the second answer here Second answer and have checked it is being retrieved correctly. Update - I also used this guide.
Removing this {#r "D:\home\site\wwwroot\sharedbin\TestDataLayer.dll"} causes the editor to complain about missing assemblies, so it IS finding the dll in question.
However it will not run - it cannot find TestDataLayer.dll.
I'm only running this in the portal editor (I've not yet mastered deployment direct from a Visual Studio Project - don't laugh :P).
#r "System.Configuration"
#r "System.Data.Entity"
#r "D:\home\site\wwwroot\sharedbin\TestDataLayer.dll"
using System;
using System.Collections;
using System.Configuration;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.SqlServer;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.Net;
using TestDataLayer;
public static void Run(TimerInfo myTimer, TraceWriter log)
{
var connection = ConfigurationManager.ConnectionStrings["sql_connection"].ConnectionString;
using(var db = new SyncDbContext(connection))
{
var RK = new RKAzureTest() {TestField1 = "It finally worked?" };
db.RKAzureTests.Add(RK);
db.SaveChanges();
}
}
[DbConfigurationType(typeof(myDBContextConfig))]
public partial class SyncDbContext : System.Data.Entity.DbContext
{
public SyncDbContext(string cs) : base(cs) {}
public DbSet<RKAzureTest> RKAzureTests {get;set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class myDBContextConfig : DbConfiguration
{
public myDBContextConfig()
{
SetProviderServices("System.Data.EntityClient",
System.Data.Entity.SqlServer.SqlProviderServices.Instance);
SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
}
}
This is the function.json:
{
"frameworks": {
"net46":{
"dependencies": {
"EntityFramework": "6.1.3"
}
}
}
}
I've compiled the dll itself to .Net 4.6 after a suspicion that the Azure Functions don't support .net 4.7.1 and via Kudu uploaded the compiled dll to a sharedbin folder (checked the path a dozen times!).
This is the error thrown up:
2018-05-01T11:00:00.012 [Warning] Unable to find assembly 'TestDataLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Are you missing a private assembly file?
2018-05-01T11:00:00.012 [Error] Exception while executing function: Functions.TimerTriggerCSharp1. mscorlib: Exception has been thrown by the target of an invocation. f-TimerTriggerCSharp1__514732255: Could not load file or assembly 'TestDataLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Not quite sure what else can be left - I'm using runtime version 1.0.11702 in the Application settings as I found life got a LOT more complicated if I went onto the Beta version.
If anyone can point me to a working guide for this use case (Database first, EF 6.1.3 etc) I'd be grateful.
Any help offered gratefully received!
Thank you :)
Go to Azure Portal, create a folder called, 'bin' inside your Azure functions using CMD Shell, upload the 'TestDataLayer.dll' file to bin folder which has just been created.
#r "System.Configuration"
#r "System.Data.Entity"
#r "TestDataLayer.dll"
Project structure should look like,
AzureFunctionProjectName001
bin
TestDataLayer.dll
run.csx
project.json
project.lock.json
...
Azure functions should be able to discover your library this time. I believe, EntityFramework works just fine.

How do I load Nuget packages that a custom DLL depends on?

I'm developing a Function App via the Portal (not local development). I have a custom DLL that depends on 1 nuget package: Entity Framework 6.1.3
I have uploaded my DLL to "../bin" and my code compiles successfully when I reference my DbContext object. So far, so good.
I also have a Project.json file and I see it acquiring the nuget packages when I save. So far, so good.
{
"frameworks": {
"net46":{
"dependencies": {
"EntityFramework": "6.1.3"
}
}
}
}
My Run.csx code compiles successfully and looks like this:
#r "../bin/Library.dll"
using System;
public static void Run(TimerInfo myTimer, TraceWriter log)
{
log.Info("My code: Started");
log.Info(typeof(Library.MyContext).ToString());
}
However, the code doesn't actually run (I don't even see the "My code: Started" log item). The error I receive is:
2017-02-27T06:37:28.731 Exception while executing function:
Functions.TimerTriggerCSharp1. mscorlib: Exception has been thrown by
the target of an invocation. f-TimerTriggerCSharp1__-205940111: Could
not load file or assembly 'EntityFramework, Version=6.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its
dependencies. The system cannot find the file specified.
My custom DLL is the simplest possible EF-referencing DLL I can possibly make. All you need to recreate it is this:
Custom DLL packages.config:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="6.1.3" targetFramework="net46" />
</packages>
Custom DLL Class1.cs
using System.Data.Entity;
namespace Library
{
public class MyContext : DbContext
{
}
}
What am I doing wrong that is keeping my custom DLL from being able to utilize the downloaded EntityFramework nuget package?
Just to verify that my nuget references are actually working, if I comment out most of my Run.csx code and replace it with this line, all executes correctly and logs what you would expect:
log.Info($"My code: {typeof(System.Data.Entity.DbContext).ToString()}");
As somebody suggested, I have tried changing my Run.csx references to look like this and it doesn't change the runtime error I get (it does compile so the path is correct):
#r "../../../data/Functions/packages/nuget/entityframework/6.1.3/lib/net45/EntityFramework.dll"
#r "../bin/My.dll"
I can also change my Run.csx file to contain this code and it does successfully execute:
using System;
public static void Run(TimerInfo myTimer, TraceWriter log)
{
log.Info(typeof(MyContext).ToString());
}
public class MyContext : System.Data.Entity.DbContext
{
}
In order to consume the assemblies coming from your referenced packages, you can deploy your custom dependency as a private assembly:
Deploy the assembly into a bin folder, in your function folder (e.g. wwwroot\myfunction\bin)
Reference the assembly without the relative path, by file name only (e.g. Library.dll)
If you wish to use shared assemblies, deployed to a common location and referenced as you have above, you'd need to deploy the assembly with its dependencies (essentially the output from your project build).
Another option that I would recommend if you want to take advantage of the shared model is to deploy your dependency as a NuGet package (which you can deploy to either a custom source hosted somewhere or as a file), that package would then specify its package dependencies and they would all be resolved automatically.
Looks like configuration problem, you need to define the reference in the project file to be copied to output.
In the Solution Explorer, expand the project, References, right click the EntityFramework, Properties, Set Copy Local = true.
Sometimes the default value is false, so then it will not in the output folder of the project.
I hope this helps.

Nuget packages with common Names

I was playing with NuGet so I created a project, wrote two simple functions (multiply and add), packaged it with the following spec:
<metadata>
<id>Math</id>
<version>1.0.0.0</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<copyright>Copyright 2015</copyright>
<tags>Matematica, Test</tags>
</metadata>
Then publicized it on my local NuGet.Server feed, added my new nuget package in another sample project, started it and it returns this:
Could not load file or assembly 'Math, Version=1.0.0.0, Culture=en-GB, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Googled for various time but found nothing (was I the only dumb enough to call a temporary package 'Math'?), so I imagined that somewhat my module name was taboo, changed it into Math_Test, same source code and it worked like a charm.
Is there some more informations out there that specifies which values are taboo?
I can't find anything on nuget official documentation.
The class Math is specified in the following dll (mscorlib.dll) so it doesn't even have the same id...
#region Assembly mscorlib.dll, v4.0.0.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll
#endregion
EDIT:
And here is the code of the sample application
using Math;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int a = -1;
try
{
Common e = new Math.Common();
a = e.Multiply(3, 2);
}
catch (Exception e)
{
System.Console.Out.Write(e);
}
System.Console.Out.Write(a);
System.Console.Read();
}
}
}
Seems like the problem was not the name but the Culture inside the Assembly (which is not the same as the language specified into Nuget spec.
Changing the AssemblyCulture from
[assembly: AssemblyCulture("en-GB")]
to
[assembly: AssemblyCulture("")]
solved the issue.
I found the warning by toggling diagnostic output during build, as suggested by #ShyamalDesai
CSC : warning CS1607: Assembly generation -- Referenced assembly 'Math' has different culture setting of 'en-GB'

Hangfire.Mongo cannot be referenced in Visual Studio 2013

I did this:
Created new WebAPI project in Visual Studio 2013
Package Manager Console: Install-Package HangFire
Package Manager Console: Install-Package HangFire.Mongo
Put the example code in Global and created the example Startup class described here https://github.com/sergun/Hangfire.Mongo
When I compile I get the error The type or namespace name 'Mongo' does not exist in the namespace 'Hangfire' for Hangfire.Mongo namespace, but I clearly have the reference.
You probably are using an old target framework. It happened the same thing to me a while back.
Check your project properties -> Application -> Target framework and make sure it's at least .NET Framework 4.5.1

Building and loading file in NUnit

I am following a book called "The Art of Unit Testing". I have reached a point where I need to test my test method that I have writtent using NUNit. The author instructs to build the project and then locate the path to the assembly file that was built and give the path to NUnit for testing.
My problem is that I cant seem to get this Assembly file path. Where is it located?
Plus, when I run my code, I am getting the following error:
Error 2 Program 'c:\Users\Documents\Visual Studio 2012\Projects\Loganalyzer\Loganalyzer\obj\Debug\Loganalyzer.exe' does not contain a static 'Main' method suitable for an entry point c:\users\documents\visual studio 2012\Projects\Loganalyzer\Loganalyzer\CSC Loganalyzer
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Loganalyzer
{
public class LogAnalyzer
{
public bool IsValidLogFileName(string fileName)
{
if (!fileName.EndsWith(".SLF"))
{
return false;
}
return true;
}
}
}
I am following the exact example that's in the book but cant get it to work as you can see. I will appreciate your help folks.
using Loganalyzer;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LogAnalyzerTest
{
[TestFixture]
class LogAnalyzerTest
{
[Test]
public void IsValidFileName_validFile_ReturnsTrue()
{
//Arrange ( Arranges objects, creating and setting them up as necessary).
LogAnalyzer analyzer = new LogAnalyzer();
//Act
bool result = analyzer.IsValidLogFileName("whatever.SLF");
//Assert ( Asserts that something is as expected)
Assert.IsTrue(result, "file name should be valid");
}
}
}
It seems as though you're trying to run your class project Loganalyzer, but you'll probably be wanting to use some sort of test runner. I prefer TestDriven.net.
NUnit is just the testing framework (very simplified, it specifies the rules for how to set up tests, etc).
What you need is some application or plugin to actually run them. You run the tests in the concole runner, or the GUI runner that come with NUnit for example, or in TestDriven.net (which I've heard is excellent).
Personally, I use the runner that comes with Resharper (although that is only free to try for a month or so).
The point is that you don't have an executable project, but rather a class library, containing stuff to test. The runner runs your tests, which in turn, call your code.
If you want to use the native nunit runner you typically use a class like this
static class NUnitLauncher
{
[STAThread]
static void Main()
{
AppEntry.Main(new[] { Assembly.GetExecutingAssembly().Location });
}
}
You'll also have to have it set as the start-up object (in the project's properties).
You'll also need to reference nunit-gui-runner.dll which you can find in the nunit install directory (normally program files). Mine is at
C:\Program Files (x86)\NUnit 2.5.7\bin\net-2.0\lib
The native nunit runner has it's problems but I find the resharper (6.1) test runner is unstable when debugging - it sometimes bombs out randomly. It also doesnt understand all the different types of parameterised tests you can have in nunit. Hopefully this isnt the case in the newer versions - it's got a much nicer UI.
The problems you describe above are two seperate things - one sounds like it is because you dont have a startup object set; the other sounds like it is confusion about what an assembly is. The executable that gets produced when you compile will contain an assembly - if you point nunit at that then it should work (assuming it has some nunit stuff in there (eg stuff tagged up with [Test] etc))