yakivyusin / SimpleNetNlp

.NET NLP library
MIT License
48 stars 9 forks source link

IOException when using in the back end of an MVC 5 web site. #2

Closed PhilHolroyd closed 6 years ago

PhilHolroyd commented 6 years ago

I'm getting the following error when trying to use the Sentence class inside an MVC controller :-

**Inner Exception 1: RuntimeIOException: java.io.IOException: Unable to open "edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz" as class path, filename or URL

Inner Exception 2: IOException: Unable to open "edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz" as class path, filename or URL**

I thought it might be a permissions issue but I can load the file bytes with the following code in the controller :-

var binFolderPath = System.Web.HttpContext.Current.Server.MapPath("~/bin/");

var fileBytes= System.IO.File.ReadAllBytes(binFolderPath + "\edu\stanford\nlp\models\lexparser\englishPCFG.ser.gz");

Thanks in advance for any assistance.

PhilHolroyd commented 6 years ago

I've taken another look through the stack trace. Just out of interest, would it be possible to expose the 'loadModel' method through your wrapper.

PhilHolroyd commented 6 years ago

This was an issue with how the current working directory is reported in an ASP.NET application.

When you call Directory.GetCurrentDirectory() is comes back with C:\Windows\System32\inetsrv. I expect it was looking for the models in a subdir of inetsrv instead of the application bin folder.

I did the following in Application_Start() in Global.asax :-

Directory.SetCurrentDirectory(System.Web.HttpContext.Current.Server.MapPath("~/bin/"));

Which worked. I don't know if this is good practice or not. I might still be a good idea to provide an interface for manually loading the models if possible.

yakivyusin commented 6 years ago

Hi, PhilHolroyd!

Thank you for your detailed report :)

I'm very glad that you solved this problem yourself. I'll think about adding an interface for manually loading models in next releases.

PhilHolroyd commented 6 years ago

Thanks. I wonder, would it be possible to only load the models once, then have them cached and used across all instances of the sentence class.

yakivyusin commented 6 years ago

But it is already worked as you described. Each model is loads from current directory only once on first use of it (when you call method that requires this model).

You can test it with same code:

// Default current directory with models
var doc = new Document("My first doc. It has sentences!");
// Lemmas Property requires PosTagger model, so it loaded here
var lemmas = doc.Sentences.SelectMany(x => x.Lemmas).ToList();

// Change current directory to some directory without models
Directory.SetCurrentDirectory("Nothing here");

// Create new Document
doc = new Document("Yet another doc. With sentences.");
// It works because PosTagger model is already loaded
lemmas = doc.Sentences.SelectMany(x => x.Lemmas).ToList();
// It doesn't work because NerTags requires PosTagger and Ner models.
// Ner model wasn't loaded and current directory doesn't have this model - throw exception.
var ner = doc.Sentences.SelectMany(x => x.NerTags).ToList();
PhilHolroyd commented 6 years ago

Ok thank you. I need to use the api differently.

PhilHolroyd commented 6 years ago

I recently got back to working on my application.

I found a further issue. The 'edu' model directory wasn't being deployed to the bin directory when I published the site to a local folder or to Azure.

I resolved by adding the following to the project file

`

CustomCollectFiles; $(CopyAllFilesToSingleFolderForPackageDependsOn);
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForMsdeployDependsOn);
  </CopyAllFilesToSingleFolderForMsdeployDependsOn>

<_CustomFiles Include="$(TargetDir)\edu\**\*.*" /> bin\edu\%(RecursiveDir)%(Filename)%(Extension) ` I hope others find this useful.