System.MissingMethodException after adding an optional parameter
Asked Answered
M

1

40

I am getting error of System.MissingMethodException after I have an optional parameter in one component and the other component which call it was not build as it call it with old number of parameters.

Only component in which parameter is added was build an deployed as patch. The calling component is old as there is no change in it.

When the calling component run it gives error :

Exception Information

Exception Type: System.MissingMethodException Message: Method not found: 'LabelURLs IPSD.BnB.Transaction.Postage.GetLabelURLs(System.String)'. Data: System.Collections.ListDictionaryInternal TargetSite: Void GenerateScanForm(Int32, Int32) HelpLink: NULL Source: BnBDispenseQueueProcess

As far as i know it should not raise an error as new parameter is optional. One more thing calling component(EXE) run as windows service.

we found an very wired workaround to make it run. By Removing the changed component once and run calling component which will say DLL not found. The place the same DLL again and calling component works fine:).

I think i am missing some internals of .net.

Let me know if more info needed.

Multimillionaire answered 27/3, 2012 at 6:52 Comment(3)
We added optional param to One of our common library. That broke all the running modules (We are lucky, it was on testing env). These are fancy development time features of .net, looks like we have to deeply understand them before using it. Thanks for asking this.Parkerparkhurst
@Parkerparkhurst please let me know your finding. as was not able to understand completely why it behaved like this. may be some compilation trick happening behind sceneMultimillionaire
@Sanddep as Jon Skeet mentioned, optional params are compile time feature. On Compile time in Caller assembly, optional param values are passed with default values. so if you added a optional param to common library make sure you are compiling caller assembly as well. If you dont want to compile all caller assembly better dont use optional param, use a overloaded method instead;Parkerparkhurst
L
58

Only component in which parameter is added was build an deployed as patch. The calling component is old as there is no change in it.

There should be a change in it, because the old code calls a method which no longer exists!

As far as i know it should not raise an error as new parameter is optional.

That's not an execution-time decision - it's a compile-time decision. If you have a method like this:

void Foo(int x, int y = 5)

and you call it like this:

Foo(10);

then the compiler effectively converts that into a call of:

Foo(10, 5);

The call has the full argument list in the binary. If you want to go from the single-parameter version to the multi-parameter version in a way which doesn't affect binary compatibility, you'd have to add an overload instead, e.g.

void Foo(int x)
{
    Foo(x, 5);
}

void Foo(int x, int y)
{
    ...
}

Alternatively, you could rebuild the calling code and redeploy that as well.

I'm deeply suspicious of your workaround. Are you sure you when you put the DLL back in place you replaced it with the new version (with the optional parameter) rather than the old version?

Lysander answered 27/3, 2012 at 6:56 Comment(9)
yes I replace with new version only. Your answer make sense. But because of the workaround it dose not looks completely true in my case .Multimillionaire
@sandeep: I strongly suspect there's something about your diagnosis of the workaround which is incorrect. How many times have you tried that? Have you definitely seen it using the new code? Have you definitely not replaced the calling code? It simply shouldn't work - there's nothing in place to do this in C#, unless you're using dynamic typing.Lysander
@sandeep: Sorry, I don't understand what your previous comment means.Lysander
One update related to replacment of DLL.... I am not replacing the called component. When I am getting error I just remove calling component and start windows service, service give error and not able to start as dll is missing. And again place the same calling dll and start service now it work fine. So I guess it is something related to JIT compiler. but not sure how it works only if I remove dll once :).Multimillionaire
@sandeep: No, it really shouldn't be. If you've still got mismatched binaries, it really, really shouldn't work. Are you sure you replaced it with the "old" binary rather than a recompiled one?Lysander
Yes 100% true I am replacing old dll only. One more thing the we are calling method at runtime through reflection not direct reference. Does this make any difference.Multimillionaire
@sandeep: Yes, it'll make a huge difference. It doesn't explain the workaround, but it makes everything else somewhat irrelevant. You really need to think about important information like this when asking a question. Please post the code you're using to call the method.Lysander
For some reason I am not able to give code but i can explain you whats happening. lets assume there are three component C1, C2 and C3. C1 load C2 dynamically and call a function foo of C2 and C2 in turn call function foo3 in C3 which is a direct reference. Hope this is clear..... We have added optional parameter in foo3 of C3 and build C3 and deployed it. no build was taken of C1 and C2 so now C2 is giving error while calling foo3 of C3...And that workaround is working i have cheeked it many time :(Multimillionaire
@sandeep: It's not really clear, to be honest. Even if you can't give the real code, you should be able to give a short but complete program which demonstrates how you're calling the method which is the important part, after all.Lysander

© 2022 - 2024 — McMap. All rights reserved.