Unable to unload DLL in .NET Core 3 - dll

I am trying to unload an external assemble but it still sitting in the memory and I can not delete the dll file. Here is my code - What am I doing wrong ?
The uploaded dll is very simple - just 1 class and one method. no dependencies.
I had a look at many samples and see no issue in the code but it still does not work.
Thank you !
class SimpleUnloadableAssemblyLoadContext : AssemblyLoadContext
{
public SimpleUnloadableAssemblyLoadContext( ) : base(isCollectible: true)
{
}
protected override Assembly Load(AssemblyName name)
{
return null;
}
}
public class PluginLoader2
{
[MethodImpl(MethodImplOptions.NoInlining)]
public string getExternalText()
{
string res = "";
var sourcesPath = Path.Combine(Environment.CurrentDirectory, "Plugins");
string[] fileEntries = Directory.GetFiles(sourcesPath);
foreach (string fileName in fileEntries)
{
SimpleUnloadableAssemblyLoadContext context = new SimpleUnloadableAssemblyLoadContext();
WeakReference w_r = new WeakReference(context, trackResurrection: true);
var myAssembly = context.LoadFromAssemblyPath(fileName);
context.Unload();
for (var i = 0; i < 10 && w_r.IsAlive; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
res += "<br /><br />" + fileName + " live status is " + w_r.IsAlive.ToString();
}
return res;
}
}

Related

Download the file as a zip in ASP.NET Core

I am designing an educational site. When the user downloads a training course, I want this download (training course) to be done in the form of compression (zipper), please give a solution
My code:
public Tuple<byte[],string,string> DownloadFile(long episodeId)
{
var episode=_context.CourseEpisodes.Find(episodeId);
string filepath = Path.Combine(Directory.GetCurrentDirectory(),
"wwwroot/courseFiles",
episode.FileName);
string fileName = episode.FileName;
if(episode.IsFree)
{
byte[] file = System.IO.File.ReadAllBytes(filepath);
return Tuple.Create(file, "application/force-download",fileName);
}
if(_httpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
{
if(IsuserIncorse(_httpContextAccessor.HttpContext.User.Identity.Name,
episode.CourseId))
{
byte[] file = System.IO.File.ReadAllBytes(filepath);
return Tuple.Create(file, "application/force-download", fileName);
}
}
return null;
}
I write a demo to show how to download zip file from .net core:
First , Add NuGet package SharpZipLib , create an Image Folder in wwwroot and put some picture in it.
controller
public class HomeController : Controller
{
private IHostingEnvironment _IHosting;
public HomeController(IHostingEnvironment IHosting)
{
_IHosting = IHosting;
}
public IActionResult Index()
{
return View();
}
public FileResult DownLoadZip()
{
var webRoot = _IHosting.WebRootPath;
var fileName = "MyZip.zip";
var tempOutput = webRoot + "/Images/" + fileName;
using (ZipOutputStream IzipOutputStream = new ZipOutputStream(System.IO.File.Create(tempOutput)))
{
IzipOutputStream.SetLevel(9);
byte[] buffer = new byte[4096];
var imageList = new List<string>();
imageList.Add(webRoot + "/Images/1202.png");
imageList.Add(webRoot + "/Images/1data.png");
imageList.Add(webRoot + "/Images/aaa.png");
for (int i = 0; i < imageList.Count; i++)
{
ZipEntry entry = new ZipEntry(Path.GetFileName(imageList[i]));
entry.DateTime= DateTime.Now;
entry.IsUnicodeText = true;
IzipOutputStream.PutNextEntry(entry);
using (FileStream oFileStream = System.IO.File.OpenRead(imageList[i]))
{
int sourceBytes;
do
{
sourceBytes = oFileStream.Read(buffer, 0, buffer.Length);
IzipOutputStream.Write(buffer, 0, sourceBytes);
}while (sourceBytes > 0);
}
}
IzipOutputStream.Finish();
IzipOutputStream.Flush();
IzipOutputStream.Close();
}
byte[] finalResult = System.IO.File.ReadAllBytes(tempOutput);
if (System.IO.File.Exists(tempOutput)) {
System.IO.File.Delete(tempOutput);
}
if (finalResult == null || !finalResult.Any()) {
throw new Exception(String.Format("Nothing found"));
}
return File(finalResult, "application/zip", fileName);
}
}
when I click the downloadZip ,it will download a .zip file
The simple example that follows illustrates the use of the static ZipFile.CreateFromDirectory method which, despite the fact that it is in the System.IO.Compression namespace , actually resides in the System.IO.Compression.FileSystem assembly, so you need to add a reference to that in your controller.
[HttpPost]
public FileResult Download()
{
List<string> files = new List<string> { "filepath1", "filepath2" };
var archive = Server.MapPath("~/archive.zip");
var temp = Server.MapPath("~/temp");
// clear any existing archive
if (System.IO.File.Exists(archive))
{
System.IO.File.Delete(archive);
}
// empty the temp folder
Directory.EnumerateFiles(temp).ToList().ForEach(f => System.IO.File.Delete(f));
// copy the selected files to the temp folder
files.ForEach(f => System.IO.File.Copy(f, Path.Combine(temp, Path.GetFileName(f))));
// create a new archive
ZipFile.CreateFromDirectory(temp, archive);
return File(archive, "application/zip", "archive.zip");
}
Answer from Source - MikesDotNetting

Issue with API Deleting for Team Foundation Server TFS

Hello can anyone tell me how to delete files using the API for TFS? Below is what I have but I can not get it to work any help would really be appreciated.
string[] InLocalDirectory = Directory.GetFiles(LogicAppConfig.Query(AppConfigLogic.TypeOfConfig.Path), "*", SearchOption.AllDirectories);
// Source Control
List<string> InSourceControl = new List<string>();
ItemSet SetOfItem = _ServerVersionControl.GetItems(_ServerPath, VersionSpec.Latest, RecursionType.Full);
foreach (Item GotItem in SetOfItem.Items)
{
ItemType TypeOfItem = GotItem.ItemType;
if (TypeOfItem == ItemType.File)
{
string LocalPath = _WorkspaceLocal.GetLocalItemForServerItem(GotItem.ServerItem);
InSourceControl.Add(LocalPath);
}
}
List<int> ToDeleteById = new List<int>();
foreach (string SourceFile in InSourceControl)
{
if (!IsIgnored(SourceFile) && !InLocalDirectory.Contains(SourceFile))
{
// Delete Source Control File
Item DeleteItem = _ServerVersionControl.GetItem(SourceFile);
ToDeleteById.Add(DeleteItem.ItemId);
// Update Local XML Directory
DataXml.Delete(SourceFile);
}
}
WorkItemStore wis = _CollectionTeamProject.GetService<WorkItemStore>();
wis.DestroyWorkItems(ToDeleteById);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.TeamFoundation.SourceControl.WebApi;
using Microsoft.VisualStudio.Services.WebApi;
namespace ConsoleAppX
{
class Program
{
static void Main(string[] args)
{
VssCredentials creds = new VssClientCredentials();
creds.Storage = new VssClientCredentialStorage();
VssConnection connection = new VssConnection(new Uri("https://tfsuri"), creds);
TfvcHttpClient tfvcClient = connection.GetClient<TfvcHttpClient>();
TfvcItem ti = tfvcClient.GetItemAsync("ProjectName", "$/FilePath","FileName").Result;
TfvcChange tchange = new TfvcChange(ti,VersionControlChangeType.Delete);
List<TfvcChange> change = new List<TfvcChange> { tchange };
TfvcChangeset tchangeset = new TfvcChangeset();
tchangeset.Changes = change;
tfvcClient.CreateChangesetAsync(tchangeset);
}
}
}
To delete a file, you need to use the VersionControlServer class to get an existing Workspace or create a new workspace. The workspace has a PendDelete method to create pending changes in the workspace. Then use the Workspace.Checkin method to commit them to source control:
https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.workspace.aspx
I tried the penddelete before I tried the last way of doing it. But even when I manually go and delete a file and it hits the _WorkspaceLocal.PendDelete(SourceFile); line and is inserted for deletion it does not pick up on the line if (changes.Count() > 0) and then never check in.
string[] InLocalDirectory = Directory.GetFiles(LogicAppConfig.Query(AppConfigLogic.TypeOfConfig.Path), "*", SearchOption.AllDirectories);
// Source Control
List<string> InSourceControl = new List<string>();
ItemSet SetOfItem = _ServerVersionControl.GetItems(_ServerPath, VersionSpec.Latest, RecursionType.Full);
foreach (Item GotItem in SetOfItem.Items)
{
ItemType TypeOfItem = GotItem.ItemType;
if (TypeOfItem == ItemType.File)
{
string LocalPath = _WorkspaceLocal.GetLocalItemForServerItem(GotItem.ServerItem);
InSourceControl.Add(LocalPath);
}
}
List<int> ToDeleteById = new List<int>();
foreach (string SourceFile in InSourceControl)
{
if (!IsIgnored(SourceFile) && !InLocalDirectory.Contains(SourceFile))
{
// Delete Source Control File
Item DeleteItem = _ServerVersionControl.GetItem(SourceFile);
ToDeleteById.Add(DeleteItem.ItemId);
// Update Local XML Directory
DataXml.Delete(SourceFile);
// Set for Deletion
_WorkspaceLocal.PendDelete(SourceFile);
}
}
string ConflictMessage = "";
Conflict[] conflicts = _WorkspaceLocal.QueryConflicts(new string[] { _LocalPath }, true);
foreach (Conflict conflict in conflicts)
{
if (conflict != null)
{
try
{
if (conflict.CanMergeContent)
{
conflict.Resolution = Resolution.AcceptMerge;
}
else
{
conflict.Resolution = Resolution.AcceptYoursRenameTheirs;
}
ConflictMessage += #"\n\r\n\r" + conflict.GetFullMessage();
_WorkspaceLocal.ResolveConflict(conflict);
}
catch (Exception ex)
{
LogicAppConfig.Insert(AppConfigLogic.TypeOfConfig.Message, "Error Detected Previously:\r\n\r\n" + ex.Message + "\r\n\r\n" + ex.Source + "\r\n\r\n" + ex.StackTrace + "\r\n\r\n" + LogicAppConfig.Query(AppConfigLogic.TypeOfConfig.Path));
}
}
}
if (!String.IsNullOrEmpty(ConflictMessage))
{
LogicAppConfig.Insert(AppConfigLogic.TypeOfConfig.Message, ConflictMessage);
}
PendingChange[] changes = _WorkspaceLocal.GetPendingChanges();
if (changes.Count() > 0)
{
int ChangeSetId = _WorkspaceLocal.CheckIn(changes, _WorkspaceName + " Deleted by Member Collaboration Utility");
}

autodesk design automation

FATAL ERROR: Unhandled Access Violation Reading 0x0008 Exception at 1d8257a5h
Failed missing output
I finally made it work with HostApplicationServices.getRemoteFile in local AutoCAD, then migrated it to Design Automation. It is also working now. The below is the command of .NET plugin.
To have a simple test, I hard-coded the URL in the plugin. you could replace the URL with the workflow at your side (either by an json file, or input argument of Design Automation)
My demo ReadDWG the entities from the remote URL file, then wblock the entities to current drawing (HostDWG), finally save current drawing.
Hope it helps to address the problem at your side.
.NET command
namespace PackageNetPlugin
{
class DumpDwgHostApp: HostApplicationServices
{
public override string FindFile(string fileName,
Database database,
FindFileHint hint)
{
throw new NotImplementedException();
}
public override string GetRemoteFile(Uri url,
bool ignoreCache)
{
//return base.GetRemoteFile(url, ignoreCache);
Database db =
Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument.Database;
string localPath = string.Empty;
if (ignoreCache)
{
localPath =
Autodesk.AutoCAD.ApplicationServices.Application.
GetSystemVariable("STARTINFOLDER") as string;
string filename =
System.IO.Path.GetFileName(url.LocalPath);
localPath += filename;
using (var client = new WebClient())
{
client.DownloadFile(url, localPath);
}
}
return localPath;
}
public override bool IsUrl(string filePath)
{
Uri uriResult;
bool result = Uri.TryCreate(filePath,
UriKind.Absolute, out uriResult)
&& (uriResult.Scheme == Uri.UriSchemeHttp ||
uriResult.Scheme == Uri.UriSchemeHttps);
return result;
}
}
public class Class1
{
[CommandMethod("MyPluginCommand")]
public void MyPluginCommand()
{
try {
string drawingPath =
#"https://s3-us-west-2.amazonaws.com/xiaodong-test-da/remoteurl.dwg";
DumpDwgHostApp oDDA = new DumpDwgHostApp();
string localFileStr = "";
if (oDDA.IsUrl(drawingPath)){
localFileStr = oDDA.GetRemoteFile(
new Uri(drawingPath), true);
}
if(!string.IsNullOrEmpty(localFileStr))
{
//source drawing from drawingPath
Database source_db = new Database(false, true);
source_db.ReadDwgFile(localFileStr,
FileOpenMode.OpenTryForReadShare, false, null);
ObjectIdCollection sourceIds =
new ObjectIdCollection();
using (Transaction tr =
source_db.TransactionManager.StartTransaction())
{
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(source_db),
OpenMode.ForRead);
foreach (ObjectId id in btr)
{
sourceIds.Add(id);
}
tr.Commit();
}
//current drawing (main drawing working with workitem)
Document current_doc =
Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument;
Database current_db = current_doc.Database;
Editor ed = current_doc.Editor;
//copy the objects in source db to current db
using (Transaction tr =
current_doc.TransactionManager.StartTransaction())
{
IdMapping mapping = new IdMapping();
source_db.WblockCloneObjects(sourceIds,
SymbolUtilityServices.GetBlockModelSpaceId(current_db),
mapping, DuplicateRecordCloning.Replace, false);
tr.Commit();
}
}
}
catch(Autodesk.AutoCAD.Runtime.Exception ex)
{
Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
}
}
}
}

Osmdroid - from offline folder

I am using OSMdroid to display both online and offline data in my app. The offline data are stored in a .zip file with the required structure.
Is it possible to have these offline tiles stored in a directory (extracted .zip file with the same structure)?
Could somebody please tell me how could I achive this?
Thank you.
I am sorry. I should try more before asking. But I am leaving this question here, somebody could find it useful.
Solution:
New MapTileFileProvider. I called it MapTileFileFolderProvider, it is a lightly modified MapTileFileArchiveProvider. It is using folders instead of archives. The modifications are not perfect, it is a "hot solution" that needs someone more experienced in Java/Android to make it properly.
Benefits from loading Tiles from folders:
Faster loading of tiles (I know, I won't recognize the difference).
Easier updates focused only on changed tiles not whole map plans.
Application can download tiles when is in "online mode" and then use the downloaded Tiles offline.
MapTileFileFolderProvider - only modifications
public class MapTileFileArchiveProvider extends MapTileFileStorageProviderBase
public class MapTileFileFolderProvider extends MapTileFileStorageProviderBase {
private final boolean mSpecificFoldersProvided;
private final ArrayList<String> mFolders = new ArrayList<String>();
private final AtomicReference<ITileSource> mTileSource = new AtomicReference<ITileSource>();
...
}
public MapTileFileArchiveProvider(...)
public MapTileFileFolderProvider(final IRegisterReceiver pRegisterReceiver,
final ITileSource pTileSource,
final String[] pFolders) {
super(pRegisterReceiver, NUMBER_OF_TILE_FILESYSTEM_THREADS,
TILE_FILESYSTEM_MAXIMUM_QUEUE_SIZE);
setTileSource(pTileSource);
if (pFolders == null) {
mSpecificFoldersProvided = false;
findFolders();
} else {
mSpecificFoldersProvided = true;
for (int i = pFolders.length - 1; i >= 0; i--) {
mFolders.add(pFolders[i]);
}
}
}
findArchiveFiles()
private void findFolders() {
mFolders.clear();
if (!getSdCardAvailable()) {
return;
}
String baseDirPath = Environment.getExternalStorageDirectory().toString()+"/ctu_navigator"; // TODO get from Config
File dir=new File(baseDirPath);
final File[] files = dir.listFiles();
if (files != null) {
String fileName;
for (File file : files) {
if (file.isDirectory()) {
fileName = baseDirPath + '/' + file.getName();
mFolders.add(fileName);
Utils.log(PlanTileProviderFactory.class, "Added map source: " + fileName);
}
}
}
}
#Override
protected String getName() {
return "Folders Provider";
}
#Override
protected String getThreadGroupName() {
return "folder";
}
protected class TileLoader extends MapTileModuleProviderBase.TileLoader {
#Override
public Drawable loadTile(final MapTileRequestState pState) {
ITileSource tileSource = mTileSource.get();
if (tileSource == null) {
return null;
}
final MapTile pTile = pState.getMapTile();
// if there's no sdcard then don't do anything
if (!getSdCardAvailable()) {
Utils.log("No sdcard - do nothing for tile: " + pTile);
return null;
}
InputStream inputStream = null;
try {
inputStream = getInputStream(pTile, tileSource);
if (inputStream != null) {
Utils.log("Use tile from folder: " + pTile);
final Drawable drawable = tileSource.getDrawable(inputStream);
return drawable;
}
} catch (final Throwable e) {
Utils.log("Error loading tile");
Utils.logError(getClass(), (Exception) e);
} finally {
if (inputStream != null) {
StreamUtils.closeStream(inputStream);
}
}
return null;
}
private synchronized InputStream getInputStream(final MapTile pTile, final ITileSource tileSource) {
for (final String folder : mFolders) {
final String path = folder + '/' + tileSource.getTileRelativeFilenameString(pTile);
File mapTileFile = new File(path);
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(mapTileFile));
} catch (IOException e) {
//Utils.log("Tile " + pTile + " not found in " + path);
}
if (in != null) {
Utils.log("Found tile " + pTile + " in " + path);
return in;
}
}
Utils.log("Tile " + pTile + " not found.");
return null;
}
}
Well, as far as I understand what you are trying to get... this is more or less what the standard XYTileSource is already doing.
So if you simply use a ready-to-use tile source like this one:
map.setTileSource(TileSourceFactory.MAPNIK);
you will see downloaded tiles files stored in /sdcard/osmdroid/tiles/Mapnik/
The main difference is that it adds a ".tile" extension at the end of each tile file (probably to prevent tools like Android gallery to index all those images).
If you have a ZIP file with tiles ready to use, you could extract them in this directory, and add .tile extension to each tile (355.png => 355.png.tile)
And TileSourceFactory.MAPNIK will be able to use them.

Sybase SQL request via VB-Script

I'd like to make a SQL request via a VBScript called by a CMD.
The Database is a Sybase Server and this is the problem, I can't find
any documentation about this, only MS SQL and stuff like this.
But it doesn't have to be a complex way like this, if somebody knows a small
tool that will output the request when it is executed I would be happy too.
But The main objective is, to output the requested datas as the programm (or script)
is executed.
UPDATE
I found something, that might be helpful
Dim OdbcDSN
Dim connect, sql, resultSet
OdbcDSN = "******;UID=*******;PWD=*****"
Set connect = CreateObject("ADODB.Connection")
connect.Open OdbcDSN
sql="SELECT * FROM **********..********** WHERE ******* = 1 AND Name = %given parameter%"
resultSet.Close
connect.Close
Set connect = Nothing
WScript.Quit(0)
Additonal Note: the batch (or whatever) will be executed by a a telefon client which will call the batch (or program) with a paramater, the name, of the person which is calling.
so if i can build the parameter into the query, that would be great.
I have the same task and it looks like you just cant connect using standard ADODB.Connection. I made some research and found that you should use iAnywhere.Data.SQLAnywhere lib and its own SybaseConnector.Connector to connect to Sybase.
Instead of using batch to call vb vbscript file you can make your own COM object with SybaseConnector, register it to your system and create new object or make executable that takes sonnection string and query. I can share source with you.
Set up Sybase IQ 15.4 dev edition, then create project in Visual Studio and make reference to .NET component iAnywhere.Data.SQLAnywhere.
Then use this code:
using System;
using System.Collections.Generic;
using System.Text;
using iAnywhere.Data.SQLAnywhere;
using System.Diagnostics;
using System.Data;
namespace SybaseConnector
{
public class Connector
{
private SAConnection _myConnection { get; set; }
private SADataReader _data { get; set; }
private SACommand _comm { get; set; }
private SAConnectionStringBuilder _conStr { get; set; }
public bool isDebug { get; set; }
public Connector(string UserID, string Password, string CommLinks, string ServerName, string command)
{
_conStr = new SAConnectionStringBuilder();
// dynamic
_conStr.UserID = UserID; //"dba";
_conStr.Password = Password; //"sql";
_conStr.CommLinks = CommLinks; //#"TCPIP{IP=servername;ServerPort=2638}";
_conStr.ServerName = ServerName; //"northwind";
// static
_conStr.Compress = "NO";
_conStr.DisableMultiRowFetch = "NO";
_conStr.Encryption = "NONE";
_conStr.Integrated = "NO";
this.Connect();
this.ExecuteCommand(command);
this.WriteResult();
}
public void Connect()
{
_myConnection = new SAConnection();
_myConnection.StateChange += new StateChangeEventHandler(ConnectionControl);
if (_conStr.ToString() != String.Empty)
{
try
{
_myConnection.ConnectionString = _conStr.ToString();
_myConnection.Open();
}
catch(Exception e)
{
if ((int)_myConnection.State == 0)
{
_myConnection.Dispose();
WriteDebug("Exception data:\n" + e.Data + "\n" +
"Exception message:\n" + e.Message + "\n" +
"Inner exception:\n" + e.InnerException + "\n" +
"StackTrace:\n" + e.StackTrace);
}
}
}
}
public void ExecuteCommand(string com, int timeout = 600)
{
if ((int)_myConnection.State != 0)
{
_comm = new SACommand();
_comm.CommandText = com;
_comm.CommandTimeout = timeout;
_comm.Connection = _myConnection;
try
{
_data = _comm.ExecuteReader();
}
catch (Exception e)
{
WriteDebug("Exception data:\n" + e.Data + "\n" +
"Exception message:\n" + e.Message + "\n" +
"Inner exception:\n" + e.InnerException + "\n" +
"StackTrace:\n" + e.StackTrace);
}
}
else
{
WriteDebug("Exception occured:\n" +
"Connection has been closed before the command has been executed.");
}
}
private void ConnectionControl(object sender, StateChangeEventArgs e)
{
WriteDebug(sender.GetType().ToString() + ": Connection state changed to " + e.CurrentState.ToString());
}
public void SetMaxReconnectCount(int count)
{
_reconnectCounter = count;
}
public void Dispose()
{
_comm.Dispose();
_data.Dispose();
_myConnection.Close();
_myConnection.Dispose();
}
private void WriteResult()
{
var output = new StringBuilder();
int count = _data.FieldCount;
// аппенд в строку и вывод в ивент одним объектом
for (int i = 0; i < count; i++)
{
if (i == count - 1)
{
output.Append(_data.GetName(i) + "\n");
}
else
{
output.Append(_data.GetName(i) + "\t");
}
}
while (_data.Read())
{
for (int i = 0; i < count; i++)
{
if (i == count - 1)
{
output.Append(_data.GetValue(i) + "\n");
}
else
{
output.Append(_data.GetValue(i) + "\t");
}
}
}
WriteDebug(output.ToString());
}
private void WriteDebug(string str, EventLogEntryType type = EventLogEntryType.Information)
{
System.Diagnostics.EventLog appLog = new System.Diagnostics.EventLog();
appLog.Source = "SQL SybaseConnector";
appLog.WriteEntry(str, EventLogEntryType.Information);
}
}
}
set [ComVisible(true)] flag if you gonna use it as COM object.
Compile project and register your dll with command
>regasm myTest.dll
then with your vbscript code
Dim obj
Set obj = CreateObject("SybaseConnector.Connector")
Call obj.Connector("user","password","TCPIP{IP=host;ServerPort=2638}","northwind",command)