Can any one suggest another way to integrate NodeJs in .Net MVC application? I am now using the following code:
public class Startup
{
public async Task<object> Invoke(dynamic input)
{
DepartmentRep person = new DepartmentRep(new MvcAppUsingEdgeJSMongoDbContext());
var department= person.GetAllDepartments();
//var department = "hello";
return department;
}
}
public class DepartmentController : Controller
{
DepartmentRepository departmentRepository = new DepartmentRepository(new MvcAppUsingEdgeJSMongoDbContext());
string connectionString = ConfigurationManager.AppSettings["connectionString"].ToString();
public ViewResult Index()
{
// var clrMethod = Edge.Func("DepartmentRep.cs");
var getData = Edge.Func("./DepartmentRep.dll");
// return View(clrMethod);
return View(departmentRepository.GetAllDepartments());
}
}
It seems to me, you may have a misunderstanding of the EdgeJs use case.
Your Startup/Invoke class/Signature is meant to be called from Node(JavaScript),
And from the code you are showing it looks like you are loading .Net from .Net
Also , as the Invoke signature suggest, It should be asynchronous.
If you want to use node from .Net side. You should check the project documentation from
scripting-nodejs-from-clr downwards.
var func = Edge.Func(#"
return function (data, callback) {
callback(null, 'Node.js welcomes ' + data);
}
");
As you can see there the wrapped code is Javascript, this time running in .Net more specifically running in Node.
The perfect use case IMMO is the Socket-Server, that is, something Node does better than .Net (IMMO again)
Which is in perfect contrast with the .Net Ado Sql Server access from NodeJs, a .Net Specialization from NodeJs context
Related
I am writing some integration tests for my web API, which means that it has to be running during the execution of the tests. Is there any way to run it with an in-memory database instead of a real one based on SQL Server?
Also, I need to run a few instances at a time, so I need somehow to change the base address of each of them to be unique. For example, I could append to the base URL these instance IDs, that are mentioned in the code below.
Here is the code which I am using to run a new instance for my tests:
public static class WebApiHelper
{
private const string ExecutableFileExtension = "exe";
private static readonly Dictionary<Guid, Process> _instances = new();
public static void EnsureIsRunning(Assembly? assembly, Guid instanceId)
{
if (assembly is null)
throw new ArgumentNullException(nameof(assembly));
var executableFullName = Path.ChangeExtension(
assembly.Location, ExecutableFileExtension);
_instances.Add(instanceId, Process.Start(executableFullName));
}
public static void EnsureIsNotRunning(Guid instaceId)
=> _instances[instaceId].Kill();
}
Talking in general, is this a good way to create test instances, or maybe I am missing something? Asking this, because maybe there is another 'legal' way to achieve my goal.
Okay, so in the end, I came up with this super easy and obvious solution.
As was mentioned in the comments - using the in-memory database is not the best way to test, because relational features are not supported if using MS SQL.
So I decided to go another way.
Step 1: Overwrite the connection strings.
In my case, that was easy since I have a static IConfiguration instance and was need just to overwrite the connection string within that instance.
The method looks as follows:
private const string ConnectionStringsSectionName = "ConnectionStrings";
private const string TestConnectionStringFormat = "{0}_Test";
private static bool _connectionStringsOverwitten;
private static void OverwriteConnectionStrings()
{
if (_connectionStringsOverwitten)
return;
var connectionStrings = MyStaticConfigurationContainer.Configuration
.AsEnumerable()
.Where(entry => entry.Key.StartsWith(ConnectionStringsSectionName)
&& entry.Value is not null);
foreach (var connectionString in connectionStrings)
{
var builder = new SqlConnectionStringBuilder(connectionString.Value);
builder.InitialCatalog = string.Format(TestConnectionStringFormat,
builder.InitialCatalog);
MyStaticConfigurationContainer.Configuration[connectionString.Key] = builder.ConnectionString;
}
_connectionStringsOverwitten = true;
}
Of course, you would need to handle the database creation and deletion before and after running the tests, otherwise - your test DBs may become a mess.
Step 2: Simply run your web API instance within a separate thread.
In my case, I am using the NUnit test framework, which means I just need to implement the web API setup logic within the fixture. Basically, the process would be more or less the same for every testing framework.
The code looks as follows:
[SetUpFixture]
public class WebApiSetupFixture
{
private const string WebApiThreadName = "WebApi";
[OneTimeSetUp]
public void SetUp() => new Thread(RunWebApi)
{
Name = WebApiThreadName
}.Start();
private static void RunWebApi()
=> Program.Main(Array.Empty<string>());
// 'Program' - your main web app class with entry point.
}
Note: The code inside Program.Main(); will also look for connection strings in the MyStaticConfigurationContainer.Configuration which was changed in the previous step.
And that's it! Hope this could help somebody else :)
I'm trying to insert a json like this (fieldname with a "."), in a Net Core Console Project
{"name.field" : "MongoDB", "type" : "Database"}
Using the C# code belove:
-with InsertManyOptions with BypassDocumentValidation in true
var options = new InsertManyOptions
{
BypassDocumentValidation = true,
IsOrdered = false
};
await _collection.InsertManyAsync(items, options);
But I have this exception:
Element name 'name.field' is not valid
I´m using :
C# Mongo Driver 2.5
Net Core Project
MongoDB version 4.0.3
Any idea? Thanks!
The BypassDocumentValidation can be used to bypass the JSON Schema validation. The issue you are facing, however, is due to the C# driver which explicitly prevents the use of the dot symbol . as part of a field name.
This used to be required up until MongoDB v3.6 which officially added support for fields with ".".
Looking into the internals of the C# driver you can see that the BsonWriter.WriteName method calls contains this code which throws the Exception you're seeing:
if (!_elementNameValidator.IsValidElementName(name))
{
var message = string.Format("Element name '{0}' is not valid'.", name);
throw new BsonSerializationException(message);
}
The _elementNameValidator is something that is managed internally by the driver which in fact comes with a NoOpElementNameValidator that doesn't do any validations. The driver, however, won't use this validator for "normal" collections.
All that said, I would strongly advise against the use of field names with "unusual" characters anyway because this is likely to set you up for unexpected behaviour and all sorts of other issues down the road.
In order to get around this you can do one of the following things:
a) Write your own custom serializer which is an option that I would personally steer clear off if possible - it adds complexity that most of the time shouldn't be required.
b) Use the below helper extension (copied from one of the unit testing projects inside the driver) to convert the BsonDocument into a RawBsonDocument which can then successfully written to the server:
public static class RawBsonDocumentHelper
{
public static RawBsonDocument FromBsonDocument(BsonDocument document)
{
using (var memoryStream = new MemoryStream())
{
using (var bsonWriter = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults))
{
var context = BsonSerializationContext.CreateRoot(bsonWriter);
BsonDocumentSerializer.Instance.Serialize(context, document);
}
return new RawBsonDocument(memoryStream.ToArray());
}
}
public static RawBsonDocument FromJson(string json)
{
return FromBsonDocument(BsonDocument.Parse(json));
}
}
And then simply write the RawBsonDocument to the server:
RawBsonDocument rawDoc = RawBsonDocumentHelper.FromJson("{\"name.field\" : \"MongoDB\", \"type\" : \"Database\"}");
collection.InsertOne(rawDoc);
Is it possible to inject (anonymously) provider out of .js file into angular module written using typescript? I am trying to compile typescript which fails inside module definition.
Story
I have a basic enough module written using angular in typescript notation. I am trying to add a definition for adalAuthenticationService provider into the mix from adal-angular.js. Because provider is not in .d.ts format I can't use it as a reference. Converting provider to .d.ts is out of the question for now. So I am left with anonymous injection option (if there is such an option).
Controller definition
module Temp.NewModule {
interface IMainCtl {
init(): void;
b1(): void;
b2(): void;
}
class MainCtl implements IMainCtl {
hello: string;
txtb1: string;
txtb2: string;
// not sure what effect {private adalService: any} has as it doesn't seem to provide anonymity
constructor(private $scope, private $log: ng.ILogService, private Api: IApi, private adalService: any) {
var vm = this;
this.init();
// not sure if this actually does anything
var adalService = adalAuthenticationService;
}
public init() {
this.Api.getDataRx().subscribe((result) => {
this.hello = result.data.Name;
});
}
public helloWorld() {
this.$log.info('I accept your greeting');
}
public b1() {
this.txtb1 = 'Now Button 1 works';
}
public b2() {
// i am trying to call login function of adalService provider
adalService.login();
}
}
// i am trying to inject adalService provider here
app.controller('MainCtl', ['$scope','$log','Api', MainCtl, adalService]);
}
App definition
module Temp {
export module NewModule {
export var serviceRoot: string = NewModule.serviceRoot || "";
export var templatePath: string;
export var servicesFramework: any;
//Initalizes angular app
$("html").attr("ng-app", "NewModule");
export var app: ng.IModule = angular.module('NewModule', ['rx', 'ngRoute', 'AdalAngular'])
.config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider', function($routeProvider, $httpProvider, adalProvider) {
adalProvider
.init ({
tenant: 'tenant.onmicrosoft.com',
clientId: 'client_id',
extraQueryParameter: 'nux=1',
//cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
},
$httpProvider
);
}]);
}
}
Basically I am trying to bypass the compilation stage with adalAuthenticationService injected as a dependency because adal-angular.js is included. So in theory it should get picked up once page renders.
Your last line is wrong, you are injecting adalService after your controller. Furthermore, from adal documentation, the service is called adalAuthenticationService. Try something like:
app.controller('MainCtl', ['$scope','$log','Api', 'adalAuthenticationService', MainCtl]);
Anonymous injection is totally supported, you don't even need to specify any. If you do not specifiy anything, it will be considered as any.
If you want to take advantage of IntelliSense, you can write only what you need in an adal.d.ts file without having to complete everything.
In your b2 function, you forgot a this:
public b2() {
// i am trying to call login function of adalService provider
this.adalService.login();
}
Im trying to execute javascript call from C# to the Document loaded in GeckoFX controller, im doing this:
public void evaluateScript(string command)
{
System.Diagnostics.Debug.WriteLine("evaluateScript: " + command);
using (Gecko.AutoJSContext context =
new AutoJSContext(geckoWebBrowser1.Window.JSContext))
{
string result;
context.EvaluateScript(
command,
(nsISupports)geckoWebBrowser1.Window.DomWindow,
out result);
}
}
But this doesn't work, I only found as a solution to call geckoWebBrowser1.Navigate('javascript:functionName(1,2);'); but with this, I can't recover return data from functionName and using the Navigate to make a JavaScript call I think is an error. Is there no way to call JavaScript functions in the DOM and receive their data in C#?
I found the solution, in the version 33, the API has changed a little, its more simple, because by default the EvaluateScript get the WebBrowser DOM as default context if you pass the param, and return the result direct.
public void evaluateScript(string command)
{
System.Diagnostics.Debug.WriteLine("evaluateScript: " + command);
using (Gecko.AutoJSContext context = new AutoJSContext(geckoWebBrowser1.Window.JSContext))
{
var result = context.EvaluateScript(command, geckoWebBrowser1.Window.DomWindow);
}
}
In the older versions, need to specify the context of the EvaluateScript, i found examples in this URL: https://nhabuiduc.wordpress.com/2014/09/18/geckofx-net-webbrowser-setup-and-features/
I have a sample snippet to invoke a class having some parameters. Below code works fine with desktop applications which targeted to the .net framework
public class MyClass
{
public MyClass(int value, string str)
{
}
}
public MainWindow()
{
InitializeComponent();
object[] ctorvalues = new object[2];
ctorvalues[0] = 1;
ctorvalues[1] = "vimal";
Type type = typeof(MyClass);
var info = type.GetConstructors().FirstOrDefault();
var param = info.GetParameters();
info.Invoke(ctorvalues);
}
I have to achieve the same in Windows Store App, I am not able to find any method to get the constructor info. Could anyone please help me on this. Please suggest some alternative way if possible. Thanks in Advance
Yeah, there are new 'reflection' APIs you need to use for Windows Store apps (though these new APIs will also work on the desktop). See more here: http://msdn.microsoft.com/en-us/library/hh535795(v=vs.110).aspx