Project

Profile

Help

Bug #4463

error when using an external function in .net

Added by Trond Husø 6 months ago. Updated 6 months ago.

Status:
New
Priority:
Low
Category:
.NET API
Sprint/Milestone:
-
Start date:
2020-02-24
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
Fix Committed on Branch:
Fixed in Maintenance Release:

Description

Continuing the thread from the a-mail here.

This is the error code the error produces: err:XPST0017

which is: It is a static error if the expanded QName and number of arguments in a static function call do not match the name and arity of a function signature in the static context.

(I'll add more later today)

Btw: hope this is the correct way to report.

History

#1 Updated by Trond Husø 6 months ago

The following errors occurs when compiling the xslt:

2020-02-24 19:05:00,271 [6 ] ERROR ErrorAppenderLogger [FIS2NITF] [(null)] - Error message: Cannot find a matching 2-argument function named {clitype:XsltTools.XsltFunctions?from=file///C:/Visual Studio Projects/Projects/NTBNormalizerService/trunk/NTBNormalizerService/bin/Debug/XsltTools/XsltFunctions/XsltFunctions.dll}SportCalculateTimeFromWinner(). For diagnostics on calls to .NET methods, use the -TJ command line option or call processor.SetProperty("http://saxon.sf.net/feature/trace-external-functions", "true")

The external dll is defined like this: xmlns:ntb="clitype:XsltTools.XsltFunctions?from=file:////c:/XsltTools/XSLTFunctions.dll"

Called like this: <xsl:value-of select="ntb:SportCalculateTimeFromWinner($WinnerTime, $CurrentTime)"/>

The processor is created like this:

public Processor CreateProcessor()
        {
            // Create the processor
            var processor = new Processor();
            processor.SetProperty("http://saxon.sf.net/feature/trace-external-functions", "true");
            processor.SetProperty(FeatureKeys.GENERATE_BYTE_CODE, "false");

            return processor;
        }

The xslt is compiled like this: public void CompileXsltDocument(Processor processor) { // Create a compiler

        var compiler = processor.NewXsltCompiler();
        
        
        compiler.ErrorList = new List<Exception>();
        try
        {
            Logger.Debug("Creating the transformer");
            if (new FileInfo(this.FileXsl).Exists)
            {
                
                this.Transformer = compiler
                    
                    .Compile(new Uri(this.FileXsl))
                    .Load();
            }
            else
            {
                throw new NormalizerException("XSLT file not found!");
            }
        }
        catch (Exception exception)
        {
            
            Logger.Error("something happened when creating the transformer");
            Logger.Error("Please check the error log for more information");
            ErrorLogger.Error(exception);

            foreach (var errorMessage in compiler.ErrorList)
            {
                ErrorLogger.ErrorFormat("Error message: {0}", errorMessage);
            }
            throw;
        }
    }

I am using the EE version of Saxon - Version 9.4.0.6

#2 Updated by Michael Kay 6 months ago

  • Category set to .NET API
  • Assignee set to O'Neil Delpratt

#3 Updated by Michael Kay 6 months ago

Handing this one over to you, O'Neil. The thread has been running a while on the saxon-help Sourceforge list. He's using 9.4 but I don't think things have changed much since then (except we might produce better diagnostics these days).. I think it's basically a dynamic loading problem on .NET, but he's not managing to get much in the way of useful diagnostics.

#4 Updated by Trond Husø 6 months ago

Would the license cover an upgrade to latest version? I can try and reference that one. Can't hurt trying I guess.....

#5 Updated by Trond Husø 6 months ago

After installing and referencing 9.9 and looking at underlying exception I see this:

at net.sf.saxon.style.Compilation.compileSingletonPackage(Configuration config, CompilerInfo compilerInfo, Source source) at net.sf.saxon.s9api.XsltCompiler.compile(Source source)

My gut feeling tells me this could have something to do with security settings, but I am not sure. I have also tested with adding the dll to a folder above (or below) the exe-file with no success. I have also set the security settings to allow for the same user on the server.

#6 Updated by Michael Kay 6 months ago

I don't think that the compileSingletonPackage() method is relevant to the problem.

#7 Updated by Trond Husø 6 months ago

I don't think so either. My gut feeling, again, tells me this has something todo with dll and security settings in windows.

I've also tried to create a secure dll (public key) and tested that in the xslt, same result.

#8 Updated by Michael Kay 6 months ago

I think that the last time I had an issue like this, I solved it by experimenting with different options for dynamic loading of the relevant class directly from the application code, keeping Saxon out of the way until I knew dynamic loading was possible.

If it's any help, this is the (Java) logic Saxon is using to load a .NET class/type, given the URI:

public static cli.System.Type dynamicLoad(String uri, String baseURI, boolean debug) throws XPathException {
        if (uri.startsWith("clitype:")) {
            uri = uri.substring(8);
        } else {
            throw new IllegalArgumentException("Unrecognized .NET external URI: " + uri);
        }
        String typeName;
        String queryParams;
        int q = uri.indexOf('?');
        if (q == 0 || q == uri.length() - 1) {
            if (debug) {
                System.err.println("Misplaced '?' in " + uri);
            }
            throw new XPathException("Misplaced '?' in " + uri);
        }
        if (q > 0) {
            typeName = uri.substring(0, q);
            queryParams = uri.substring(q + 1);
        } else {
            typeName = uri;
            queryParams = "";
        }
        if ("".equals(queryParams)) {
            cli.System.Type type = cli.System.Type.GetType(typeName);
            if (type == null && debug) {
                try {
                    //noinspection ConstantIfStatement
                    if (false) {
                        throw new cli.System.TypeLoadException();
                    }
                    //noinspection UnusedDeclaration
                    cli.System.Type type2 = cli.System.Type.GetType(typeName, true);
                } catch (Exception | cli.System.TypeLoadException err) {
                    System.err.println("Failed to load type " + typeName + ": " + err.getMessage());
                    return null;
                }
                System.err.println("Failed to load type " + typeName);
            }
            return type;
        } else {
//            AssemblyName aname = new AssemblyName();
            String loadFrom = null;
            String href = null;
            String partialName = null;
            String asmName = null;
            String loc = null;
            String ver = null;
            String sn = null;
            StringTokenizer tok = new StringTokenizer(queryParams, ";&");
            while (tok.hasMoreTokens()) {
                String kv = tok.nextToken();
                int eq = kv.indexOf('=');
                if (eq <= 0) {
                    if (debug) {
                        System.err.println("Bad keyword=value pair in " + kv);
                    }
                    throw new XPathException("Bad keyword=value pair in " + kv);
                }
                String keyword = kv.substring(0, eq);
                String value = kv.substring(eq + 1);
                if (keyword.equals("asm")) {
                    asmName = value;
                } else if (keyword.equals("ver")) {
                    ver = value;
                } else if (keyword.equals("loc")) {
                    loc = value;
                } else if (keyword.equals("sn")) {
                    sn = value;
                } else if (keyword.equals("from")) {
                    loadFrom = value;
                } else if (keyword.equals("href")) {
                    href = value;
                } else if (keyword.equals("partialname")) {
                    partialName = value;
                } else if (debug) {
                    System.err.println("Unrecognized keyword in URI: " + keyword + " (ignored)");
                }
            }
            Assembly asm;
            try {
                //noinspection ConstantIfStatement
                if (false) {
                    throw new cli.System.IO.FileNotFoundException();
                }
                if (partialName != null) {
                    asm = Assembly.LoadWithPartialName(partialName);
                } else if (loadFrom != null) {
                    String abs = loadFrom;
                    if (baseURI != null) {
                        abs = ResolveURI.makeAbsolute(loadFrom, baseURI).toString();
                        if (debug) {
                            System.err.println("Absolute location URI: " + abs);
                        }
                    }
                    asm = Assembly.LoadFrom(abs);
                } else if (href != null) {
                    asm = Assembly.LoadFrom(href);
                } else {
                    String longName = asmName;
                    if (ver != null) {
                        longName += ", Version=" + ver;
                    }
                    if (loc != null) {
                        longName += ", Culture=" + loc;
                    }
                    if (sn != null) {
                        longName += ", PublicKeyToken=" + sn;
                    }
                    asm = Assembly.Load(longName);
//                    asm = Assembly.Load(aname);
                }
                if (debug) {
                    System.err.println("Assembly " + asm.get_FullName() + " successfully loaded");
                    System.err.println("Assembly codebase (" +
                            (asm.get_GlobalAssemblyCache() ? "GAC" : "local") +
                            "): " + asm.get_CodeBase());
                }
            } catch (cli.System.IO.FileNotFoundException err) {
                if (debug) {
                    System.err.println("Failed to load assembly " + uri + ": " + err.getMessage() +
                            " (FileNotFoundException)");
                }
                throw new XPathException("Failed to load assembly " + uri + ": " + err.getMessage());
            } catch (Throwable err) {
                if (debug) {
                    System.err.println("Failed to load assembly " + uri + ": " + err.getMessage() +
                            " (" + err.getClass().getName() + ")");
                }
                throw new XPathException("Failed to load assembly " + uri + ": " + err.getMessage());
            }
            cli.System.Type type = asm.GetType(typeName);
            if (type == null) {
                if (debug) {
                    System.err.println("Type " + typeName + " not found in assembly");
                }
                throw new XPathException("Type " + typeName + " not found in assembly");
            }
            return type;
        }
    }

One thing that puzzles me is that you're not seeing any messages about failure to load the class.

The other avenue you could pursue as a workaround is to explicitly register the class containing the extension function. If you drill down from the Processor object to the underlying (Java) ProfessionalConfiguration object, calling config.getExtensionBinder("clitype") will give you the DotNetExtensionLibrary, and this has a method declareDotNetType(String uri, cli.System.Type theClass). If the namespace URI of an extension function has been associated with an .NET System.Type in this way, then no dynamic loading is necessary.

Please register to edit this issue

Also available in: Atom PDF