Yortw / RSSDP

Really Simple Service Discovery Protocol - a 100% .Net implementation of the SSDP protocol for publishing custom/basic devices, and discovering all device types on a network.
http://yortw.github.io/RSSDP/
MIT License
287 stars 67 forks source link

Method not found: 'Void System.Net.Http.HttpClientHandler.set_AutomaticDecompression(System.Net.DecompressionMethods)'. #20

Closed 1iveowl closed 8 years ago

1iveowl commented 8 years ago

I'm getting the exception:

Exception thrown: 'System.MissingMethodException' in Rssdp.Portable.dll ("Method not found: 'Void System.Net.Http.HttpClientHandler.set_AutomaticDecompression(System.Net.DecompressionMethods)'.")

...when using the "Event Driven Search & Discovery via Notifications" approach.

The exception is thrown as this line is executed: var fullDevice = await e.DiscoveredDevice.GetDeviceInfo();. The line isin the deviceLocator_DeviceAvailable method as per the example provided in the Readme.md.

Any ideas what this could be?

Some of the devices discovered are fine but others result in this error.

I'm not running the Nuget, but have cloned the code base locally. I'm running this on a Windows 10 PC in an UWP App. I'm referencing the projects:

If I'm using only the Nuget I'm also getting exception, but they point to some XML parsing error???

Yortw commented 8 years ago

It sounds like the platform you're runing on doesn't support automatic decompression of gzipped http responses, but I'm sure UWP does, and having just checked the code it checks the SupportsAutomaticDecompression property before enabling that feature so if it was unsupported it shouldn't be an issue anyway.

I primarily use this in a UWP app myself, and so far haven't seen this problem. I care about fixing it, but at this point I'm lost as to why it's occurring or what to do about it.

I assume if you create your own HttpClient instance and request the description document from the discovered device url it returns a valid xml doc? While not actually a solution, a workaround for your case might be to use the GetDeviceInfo overload that accepts an httpclient instance and provide one you've created yourself without compression support.

Yortw commented 8 years ago

Thanks for reporting the issue, btw.

1iveowl commented 8 years ago

Thank you Troy for swift reply. I agree that it is strange. What is more strange is that I don't see the same exception when using the Nuget 1.0.0.10 instead of the cloned code base I get another exception:

'Element' is an invalid XmlNodeType.

It hard to tell if its the same thing triggering this.

Everything else is the same. Same code, same PC etc.

1iveowl commented 8 years ago

On a different note. How did you manage to get around the issue with MS SSDP Service seemingly "occupying" port 1900?

I'm trying to build a UPnP PCL that will run with Xamarin Forms. For this purpose I'm using the RSSDP and for implementing the UPnP Eventing part I'm using https://github.com/rdavisau/sockethelpers-for-pcl as the foundation for listening for unicasts and multicasts.

I'm pretty good with the unicasts so far, but I'm struggling with the multicast part as I get this exception when trying to do a JoinMulticastGroupAsync(IpAddr, port:1900).

Only one usage of each socket address (protocol/network address/port) is normally permitted.

I can listen for multicasts on other vacant ports, just fine and have tests that I receive those. But this helps me little as I don't receive multicasts send for port 1900 when listening on for instance port 8000. I assume that this is expected behaviour?

I've been looking at your code with a debugger and I see that managing multicasts just fine when listening for multicasts at port 1900. So I see that this is indeed possible.

I know this question is completely unrelated to this thread, so forgive me bringing this up here, but maybe you've come a cross the same bump and solved it? If not, please don't bother spending more time on my out-of-band question and feel free to delete it.

Thank you for your attention.

Yortw commented 8 years ago

I confess I don't know why you'd get a different exception, but the XML exception is also likely to occur if a compressed stream is received and not decompressed, so may be the same cause (somehow - I would still expect the same exception, given it should be the same code).

I believe there is an option (on some .Net platforms anyway, WinRT 8.0 doesn't have it for example) to open the socket in 'shared mode', (often referred to as address reuse or addreuse or similar). I think I set that socket option on, and then so long as everything else has done the same we all shared the multicast data. In my particular commercial environments I can just insist the Windows service is turned off anyway (in fact, most of our customers have it off by default), but I think it works if the reuse option is enabled. I don't recall doing anything else.

How you enable that option in .Net depends on the platform. It's different for System.Net.Sockets than it is for whatever WinRT/UWP/WPSL use.

Yortw commented 8 years ago

Could you put a break point on the line;

rawDescriptionDocument.EnsureSuccessStatusCode();

inside the DiscoveredSsdpDevice.GetDeviceInfo(bool) method and see if it hits it before the error? If so, what does the contentencoding header and body of the result (rawDescriptionDocument) look like? If the encoding says gzip or the content doesn't look like xml/text then likely you're getting a compressed response which is why the xml dom can't deserialiser it. The question would be why it's not being deserialised automatically like it's supposed to.

Yortw commented 8 years ago

One mystery solved; you can (probably) fix the method not found problem by adding the Microsoft Client HTTP Libraries nuget package to your app. Since the RSSDP portable dll references that package, your app needs to as well. The RSSDP Nuget package should add it automatically but if you're referencing your own cloned copy via project or assembly references you'll need to manually add the dependent packages.

https://davidburela.wordpress.com/2013/07/12/error-when-using-http-portable-class-library-compression/

Yortw commented 8 years ago

I ran this on a friends network instead of my home or work networks, and I was able to reproduce the issue. Apparently some devices have custom properties with child xml nodes instead of simple values and the deserialisation code doesn't cope with that (which I didn't know). I've released an updated nuget package (v1.0.11)with new deserialisation logic that I think will fix the problem. Please re-oepn this issue if it doesn't solve it for you.

1iveowl commented 8 years ago

Perfect. I fetched Nuget 1.0.11 and ran my project again (all else the same). I let it run on the network for 15 minutes and with ver. 1.0.11 I got no exception. Before I usually got an exception after approx. 2-3 minutes. Great to see this fixed so fast 👍

I have quite a few devices on my network so it represents a good test bed for this kind of stuff I guess :-)

Also, what you describe above about installing the Microsoft Network Client makes perfect sense. This also explains why I did not get the AutomaticDecompression exception when using the Nuget, as the Nuget takes care of the necessary dependencies.

I also want to thank you for pointing me in the right direction on my port UPnP 1900 issue. I think I managed to track down what is missing for it to work on UWP to this bit here: https://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.sockets.datagramsocketcontrol.multicastonly.aspx

Yortw commented 8 years ago

No problem, glad we fixed it :) Thanks for your help.That link looks like the right one for UWP/WinRT.

Just an FYI... the GetDeviceInfo method should have error handling around it in production systems. It makes a network (HTTP) call to get the device description document, and of course all the usual network problems can occur. I've even encountered some devices that broadcast invalid addesses, so just be aware that exceptions should be expected and handled.

1iveowl commented 8 years ago

Thank, yes it makes sense to be extra ready to catch exception whenever is dealing with real-world devices that are outside direct control 👍