Is it possible to execute java application (which is dependent on many 3rd party libs) from C# code using tools like IKVM/JNI4Net? - ikvm

I want to call java API from c# code. My Java API is a jar file bundled with several 3rd party libraries. I am trying to use IKVM and JNI4Net. I am able to call few java functions but when code has dependency over 3rd party libs, it shows error: NoClassDefFoundError' occurred in dll. My question is it possible to execute java application (which is dependent on many 3rd party libs) from C# code using such JNI based tools?

Without being a jni4net expert, I have some experience doing just that.
With jni4net, you need to use a BridgeSetup and call one of its AddClassPath() methods to build a classpath with your 3rd-party libraries.
For instance, something like this:
namespace My.Lib
{
using System;
using net.sf.jni4net;
public static class MyClass
{
public static void Init()
{
// create the setup and register the Java classpath
BridgeSetup bridgeSetup = new BridgeSetup(true);
bridgeSetup.AddClassPath("lib/myLib1.jar");
bridgeSetup.AddClassPath("lib/myLib2.jar");
// add others ...
// check the actual classpath we got
Console.WriteLine("registered classpath : ");
foreach (String s in bridgeSetup.JVMCLassPath) Console.WriteLine(s);
// now create the JVM
Bridge.CreateJVM(bridgeSetup);
}
}
}

Related

open-wc how to use web components in a legacy application

I had a look at the open-wc generator. I can generate web component libraries and web component application but the generated README file and the documentation does not contain a description how to import a web component library into another library or into an application so that the library or application can use the dependency as a web component. Is there a sample but non trivial application build with open-wc that I can use to learn from?
My primary interest is to import several web component into a legacy application that does not use npm and rollup by itself. What would be the best way to do that?
What I have tried to do. I have created a library litelement-demo by running
npm init #open-wc
and I have created an application in the similar way. I have opted for using typescript in both cases. The README.md of libelement-demo states that it can be used in this way:
<script type="module">
import 'litelement-demo/litelement-demo.js';
</script>
<litelement-demo></litelement-demo>
I have added this snippet to the application's index.html and run
npm i --save ../litelement-demo
npm run build
but the 2nd command fails with the error message
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
litelement-demo/litelement-demo.js (imported by inline-module-index-1.js)
The link in the error message does not help and neither the open webcomponent documentation nor the generated README.md files.
Typical web component is basically a class as follows:
// You can also use some external library and inherit from its base class.
// For example: LitElement
class BasicSetup extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// Template/DOM generation
}
// One or more methods...
}
// Registration
customElements.define('basic-setup', BasicSetup);
Have a look at a registration statement. Simply add this file in your HTML scripts section and you are done. You do not have to integrate with any existing library or solution. Wherever, you have HTML, you can simply use it as
<div>
<p>My Awesome web component</p>
<basic-setup></basic-setup>
</div>
You can also initialize the element with JavaScript using customElements.get(name) method if you do not have access to BasicSetup class reference.
// Get reference to basic-setup class assuming it is already registred.
const ClassRef = customElements.get('basic-setup');
// Initialize using constructor
const myCustomElm = new ClassRef();
// or use document.createElement
const myCustomElm = document.createElement('basic-setup');
document.body.appendChild(myCustomElm);
Since your legacy application doesn't use npm, you don't need to do anything with it an npm.
Just add in the head
<script type="module">
import 'litelement-demo/litelement-demo.js';
</script>
and then use
<litelement-demo></litelement-demo>
somewhere in your html. Nothing else needed to start working

Xamarin Forms: Open downloaded file in default Android/iOS application

I am using Xamarin Forms. I would like to download jpg file (it is done) and then open that jpg in default application on Android/iOS (opening photo browser with this photo). Of course photo is single example, I would like to open any file in default application.
I found several solutions native-only but my application is designed to be cross-platform. I though that I can use Launcher from Xamarin.Essentials package but apparently I can't.
How to achieve this?
You can have a try with Xamarin.Essentials: Launcher:
var fn = "File.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(file)
});
I found several solutions native-only
Opening something in another app is quite close to the system for a mobile application and there are some things to consider, which dependend on the platform. Usually, mobile apps run in a sandbox with very limited access to the surrounding system. Particularly this means that, if you downloaded a file to the sandbox of your app, other apps (which native viewers are), aren't allowed to access the file.
On Android, you can copy the file to a shared space (see Application.Context.GetExternalFilesDir(null)) and then open it. This might be possible with Essentials, but I'm not quite sure, but since we're on the Android platform anyway now, you could create an intent now anyway.
On iOS you create controllers from within your app (for example the QLPreviewController to preview the file) that may access items in your sandbox. Depending on the type of controller (e.g. UIActivityViewController) they may open other apps.
How to use this platform-independently?
Since you are programming a platform independent app, you'll have to take care that the correct class is called to the platform dependent work. There are several options how you can achieve this
Use the DependencyService
Use a real dependency injection framework
Use an abstract base class with initialization in the platform dependent projects
DependencyService
To use the Xamarin.Forms DependencyService you need two things
An interface for the functionality you'd like to implement
One implementation per platform
Assuming you hvae a simple interface to share a file
public IShareFile
{
void ShareFile(string fileName);
}
you can implement an implementation of this interface on each platform and add the DependencyAttribute to the assembly. e.g. for iOS:
[assembly: Dependency(typeof(MyApp.iOS.DeviceOrientationService))]
namespace MyApp.iOS
{
public class ShareFile : IShareFile
{
public void Share(string fileName)
{
// implementation goes here
}
}
}
The general scaffold is the same for Android, albeit the implementation differs.
Using a real dependency injection framework
Basically it's pretty much the same. You can skip the DependencyAttribute, though. In order to make the implementation available you'll have to get hold of the DI container from your platform specific code, which might be tricky. This might be an overshoot for a single dependency, but if you're using a DI container anyway and there are X dependencies, it might be worth the effort.
Using an abstract base class
Add an abstract base class to your project
public abstract class ShareFile
{
public static ShareFile Instance { get; protected set; }
public abstract void Share(string fileName);
}
and in your implementation in the platform specific project, you add an Init() method
internal class ShareFileImpl : ShareFile
{
public static void Init()
{
ShareFile.Instance = new ShareFileImpl();
}
public void Share(string fileName)
{
// implementation goes here
}
}
This init method must be called from your platform specific code. Most likely during initialization. The implementation can then be accessed via its abstraction from your platform independent code (of course you'll see only the abstraction, public methods added to ShareFileImpl won't be visible from your platform independent code).
ShareFile.Instance.Share(fileName);
A combination of the abstract class approach and dependency injection is also conceivable. When registering your classes in the DI framework, you could register the platform instance like
container.RegisterInstance<ShareFile>(ShareFile.Instance);
This way you can make use of the DI container features (e.g. constructor injection), while keeping the hassles of using the DI container from your platform specific project away from you. The drawback is, that you'll still have to call ShareFileImpl.Init() from your platform specfic code.

EF Core in .NET Core library

The main idea is to add a EF Core nuget package to a .NET Core library project and then use that library in a bunch of applications (e.g., ASP.NET Core, Win Service, Console App) without configuring EF in each of them. And, if possible, without adding EF packages to each of them.
I'm wondering if it's possible.
My current problem is that I can't create a database based on the model I have in the library project.
It seems I can't just select the library project in the Package Manager Console and run update-database. It wants me to implement 'IDesignTimeDbContextFactory'.
I'm using .NET Core 2.1. Would it help if I update it to the latest version?
As mentioned by the error, you need to implement IDesignTimeDbContextFactory which is part of the Microsoft.EntityFrameworkCore.Design package so go ahead and install that in your library. Then create a class that implements IDesignTimeDbContextFactory appropriately.
Since you created a .NET Core library, set that as your startup project.
Then in your Package Manager Console, select your library as the Default project and run update-database.
Yes, you can do this.
Make sure you have all the prerequisites installed.
Create a .NET Core Console app
Create a Core Class library for Entity Framework
Reference the Class library from the Console App
Scaffold your database, go to Tools > Package Manager Console
From the dropdown set your default project to your class library so it will scaffold there.
Run this in the console (database first approach): Scaffold-DbContext "Your connecting string here" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models/EF -f
Create a class to get your context
public class Context
{
// See all queries generated by EF in debug window
public static readonly LoggerFactory MyLoggerFactory
= new LoggerFactory(new[] { new DebugLoggerProvider((s, level) => level >= LogLevel.Trace) });
public static DF.Data.Models.EF.YourContext GetContext()
{
var optionsBuilder = new DbContextOptionsBuilder<DF.Data.Models.EF.YourContext>();
optionsBuilder.UseSqlServer(
"Your Connection String").UseLoggerFactory(MyLoggerFactory);
return new DF.Data.Models.EF.YourContext(optionsBuilder.Options);
}
public partial class YourContext : DbContext
{
public YourContext(DbContextOptions optionsBuilderOptions) : base(optionsBuilderOptions)
{
}
}
}
Create a Repository class to store your queries if you would like.
Note: When you scaffold the database again make sure you select the Class library project as the default project from the dropdown. Then set your other project back to the startup project.

Reducing HtmlUnit Library jar size

Hi I have written a script using HTMLUnit that fetches a web page given a url and performs certain operations on them. For instance searching for a string on a page or clicking on a link and so on. I am creating a runnable jar using eclipse IDE.
HTML-Unit consists of about 21 different library jars that i am extracting in my single final runnable jar. These dependencies cause the single jar to occupy a space of about 9.3MB. I have been trying to reduce the individual jar size using obfuscation. I am using a tool called proguard for it.
Here is a sample proguard configuration i am using to obfuscate a single library jar by the name of "commons-logging-1.1.1.jar":
`-libraryjars <java.home>/lib/rt.jar
-injars C:/Users/Desktop/Jars/commons-logging-1.1.1.jar
-outjar C:/Users/Desktop/SmallJars/commons-logging-1.1.1.jar
-printmapping C:/Users/Desktop/SmallJars/out_commons-logging-1.1.1.map
-renamesourcefileattribute SourceFile
-dontnote
-keepattributes InnerClasses,SourceFile,LineNumberTable,Deprecated
-keep public class * {
public protected *;
}
-keepclassmembernames class * {
java.lang.Class class$(java.lang.String);
java.lang.Class class$(java.lang.String, boolean);
}
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclassmembers class * implements java.io.Serializable
{
static final long serialVersionUID;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}`
The config is pretty much the same as one given on the proguard website in usage -> typical libraries. On rebuilding the project in eclipse using these 21 reduced jars and running it, the script fails at runtime with the exception:
"java.lang.NoSuchMethodException: org.apache.http.conn.ssl.SSLSocketFactory.createDefaultSSLContext()"
Looks like i have obfuscated the individual jars in a manner that certain methods will now not be found. Could you guide me as to what may be causing these exceptions. and is there something wrong with the config file above.If
so what would be the best proguard configuration for this scenario.
I am aware another member was chasing a similar problem. The question is posted at link:
[a link] (Determine used libraries to reduce JAR file size)
Thank you!!
The method is accessed by reflection, which ProGuard can't know from its static analysis. You have to preserve it in your configuration. Cfr. ProGuard manual > Troubleshooting > NoSuchMethodException.
Processing the application as a whole will be much more effective than processing the libraries individually, because ProGuard may then remove entirely unused libraries or at least larger parts of them.

Adding bindings in a test project with Ninject.MVC3

I'm having trouble figuring out what the best approach is these days for Ninject and ASP.NET MVC 3.
I have used Install-Package Ninject.MVC3 on my application and have my bootstrap class with the following methods:
public static void Start()
public static void Stop()
private static IKernel CreateKernel()
private static void RegisterServices(IKernel kernel)
It's all great and it loads my modules as expected. But historically what I have done is something like this:
MyApp.dll
Kernel.Bind<ISomething>().To<Something>();
Kernel.Bind<IBlah>().To<Blah>();
Kernel.Bind<IFoo>().To<Foo>();
MyApp.Tests.dll
Here I want to override ONLY ISomething's binding, so I used to just unbind the thing I needed to mock/whatever and rebind:
Kernel.Unbind<ISomething>();
Kernel.Bind<ISomethig>().To<TestSomething>();
But there isn't a method in the Nuget package that implies a thought through way to achieve this with the App_Start class from the original library. If I put another Ninject bootstrap class in my test app it only seems geared up to build a new kernel:
[assembly: WebActivator.PreApplicationStartMethod(typeof(TestNinjectBootstrapper), "Configure")]
I could store the kernel in the original bootstrapper statically and call from the tests project, but this feels wrong. Am I thinking too much and missing something? Or thinking too little :)
Argh. What is a good approach?
To reuse interface/class mapping registration in different project there is ability to create NInject modules. Modules just need to implement the INinjectModule interface, but most should extend the NinjectModule class for simplicity.
So you can place interface/class mapping inside module like in the following example:
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf().InSingletonScope();
}
}
After you define such module you can instantiate Kernel with mapping defined in this module.
All that you need is to specify this module as argument during creating Kernel object:
IKernel kernel = new StandardKernel(new WarriorModule());
Note that you can create and instantiate kernel with multiple modules.
So, modules will help you to reuse default mapping configuration. Mapping configuration will be defined in one place which will simplify maintance especially if there are several projects which uses the same interface/class mapping configuration.
There are also some other features like 'Dynamic Module Loading' and etc. More information about modules can be found here.

Resources