Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

xgalaxy posted:

I'm confused about how NuGet works and maybe someone can help me.
There appears to be a discrepancy in how NuGet functions between Xamarin Studio and Visual Studio.

I'm trying to add the Microsoft.CodeAnalysis nuget packages. In Xamarin Studio the only packages it adds besides the CodeAnalysis packages are System.Collections.Immutable and System.Reflection.Metadata. But in Visual Studio it is adding a ton of System.* packages that should already be installed by default (or at least I would expect them to be) such as System.Collections, System.IO, System.Linq, etc, etc. All of them tagged with 4.0.0 at the end.

Can someone explain why it is doing this?

Is it the same project between the two? What framework are you targeting?

Adbot
ADBOT LOVES YOU

ljw1004
Jan 18, 2005

rum

xgalaxy posted:

I'm confused about how NuGet works and maybe someone can help me.
There appears to be a discrepancy in how NuGet functions between Xamarin Studio and Visual Studio.
I'm trying to add the Microsoft.CodeAnalysis nuget packages. In Xamarin Studio the only packages it adds besides the CodeAnalysis packages are System.Collections.Immutable and System.Reflection.Metadata. But in Visual Studio it is adding a ton of System.* packages that should already be installed by default (or at least I would expect them to be) such as System.Collections, System.IO, System.Linq, etc, etc. All of them tagged with 4.0.0 at the end.

I can't speak to Xamarin Studio, but what you describe shouldn't be happening in VS, and I've not observed it recently...

Could you give some more detail...? (1) What version .NET are you targeting? What app type do you have? (2) Is your app consuming NuGet3 (via a project.json file) or NuGet2 (via a packages.config file)? (3) What exact version of Microsoft.CodeAnalysis are you adding? (4) Could you post a screenshot? I don't even see a 4.0.0 tag at the end of anything. (5) What version of VS are you using? (6) Are you using just the bog standard NuGet that came with VS? Or have you downloaded updates?


NuGet has gone through waves. Traditionally you'd write a package to target e.g. "net46", and it could reliably know that things like System.IO are already present. Then when VS2015 shipped the guidance changed, and the NuGet package was supposed to target "dotnet" and had to explicitly list everything like System.IO that it depended upon. Some package authors didn't bother; some packages did list them all; some packages did list them all but failed to provide a useful fallback for net40 etc.

What you describe was exactly the state of affairs 2 months ago, when a pre-release version of some System NuGet packages came out but failed to list net40 compatibility. The behavior if you target those NuGet packages was you'd get a load of useless references like you're observing. But I chatted with the author of the system NuGet packages and he indicated then that he'd change it.

In the future, NuGet package authors are supposed to shift over to target ".NET standards", but I don't know if that's available yet.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

ljw1004 posted:

What you describe was exactly the state of affairs 2 months ago, when a pre-release version of some System NuGet packages came out but failed to list net40 compatibility. The behavior if you target those NuGet packages was you'd get a load of useless references like you're observing. But I chatted with the author of the system NuGet packages and he indicated then that he'd change it.

It could be that he's using a NuGet server like ProGet that supports "pass-through" feeds to NuGet.Org and caching packages on-prem. If that's the case, then clearing the package cache might help.

xgalaxy
Jan 27, 2004
i write code
Hey guys. Thanks for the help. Here are some more details:

- It is the same solution / project file that I'm loading between Xamarin and Visual Studio.
- Latest versions of both IDE's
- Running Xamarin on OS X and Visual Studio on Windows 10.
- The project is targeting .NET Framework 4.5
- It is using packages.config not packages.json
- The project type is a console application
- Trying to add Microsoft.CodeAnaylsis 1.1.1 (which I think is the latest version)
- Using Visual Studio Nuget version (3.3.0.167)
- It is using the default? feed of nuget.org

Here you can see a screenshot of all of the System.* packages it wants to install.

ljw1004
Jan 18, 2005

rum

xgalaxy posted:

Here you can see a screenshot of all of the System.* packages it wants to install.


That "Review Changes" dialog is fine! It's just telling you that those are the dependencies. When you click through to OK, and look at your project's References node, you'll see that the only ones actually added are these:

code:
Microsoft.CodeAnalysis
Microsoft.CodeAnalysis.CSharp
Microsoft.CodeAnalysis.CSharp.Workspace
Microsoft.CodeAnalysis.VisualBasic
Microsoft.CodeAnalysis.VisualBasic.Workspace
Microsoft.CodeAnalysis.Workspaces
Microsoft.CodeAnalysis.Workspaces.Desktop
System.Collections.Immutable
System.Composition.AttributedModel
System.Composition.Convention
System.Composition.Hosting
System.Composition.Runtime
System.Compisition.TypedParts
System.Reflection.Metadata

xgalaxy
Jan 27, 2004
i write code
Nope. Like I said (or maybe I wasn't clear enough), its actually downloading and installing all of them to the packages folder.

EDIT: I see what you are saying regarding the References node though. And you are correct. They are not listed there.
This is so weird though. I wouldn't expect it to be downloading these System packages.


xgalaxy fucked around with this message at 00:37 on Dec 11, 2015

ljw1004
Jan 18, 2005

rum

xgalaxy posted:

Nope. Like I said (or maybe I wasn't clear enough), its actually downloading and installing of them to the packages folder.

EDIT: I see what you are saying regarding the References node though. And you are correct. They are listed there.
This is so weird though. I wouldn't expect it to be downloading these System packages.

It has to download them. That's the only way it can inspect their contents and determine that they don't need to be added to the References node (i.e. to your csproj). There's nothing in the name System.IO that's enough to prove to NuGet that it doesn't need to download for this particular target.

xgalaxy
Jan 27, 2004
i write code

ljw1004 posted:

It has to download them. That's the only way it can inspect their contents and determine that they don't need to be added to the References node (i.e. to your csproj). There's nothing in the name System.IO that's enough to prove to NuGet that it doesn't need to download for this particular target.

So why does Xamarin Studio not have to do this as well? It does not download these packages.

xgalaxy
Jan 27, 2004
i write code
And by the way. If I set the target framework of the project to .NET 4.0 then it doesn't download these packages. So something goofy is going on here. I've never seen the behavior you are talking about before where it has to download framework provided assemblies for nuget to work.

ljw1004
Jan 18, 2005

rum

xgalaxy posted:

And by the way. If I set the target framework of the project to .NET 4.0 then it doesn't download these packages. So something goofy is going on here. I've never seen the behavior you are talking about before where it has to download framework provided assemblies for nuget to work.

All of the framework NuGet packages have been rewritten drastically over the past few months, so they're packaged quite differently for >=4.5 things. I wrote a blog on the way NuGet works:
http://blogs.msdn.com/b/lucian/archive/2015/09/15/writing-a-nuget-package-for-vs2015-rtm-repost.aspx

There are reasonable+expected things that could cause the differences you observe! ...

* As per the blogpost, >= .net45 is special because it can now consume the "dotnet" NuGet package styles, and indeed for PCLs will prefer it over anything else.
* The correct way for a "dotnet" NuGet package to be written (like all the System.* NuGet packages) is to explicitly list out their dependencies
* Maybe Xamarin Studio hasn't updated to consume "dotnet" TFMs yet (???) I don't know where exactly it stands.

xgalaxy
Jan 27, 2004
i write code

ljw1004 posted:

All of the framework NuGet packages have been rewritten drastically over the past few months, so they're packaged quite differently for >=4.5 things. I wrote a blog on the way NuGet works:
http://blogs.msdn.com/b/lucian/archive/2015/09/15/writing-a-nuget-package-for-vs2015-rtm-repost.aspx

There are reasonable+expected things that could cause the differences you observe! ...

* As per the blogpost, >= .net45 is special because it can now consume the "dotnet" NuGet package styles, and indeed for PCLs will prefer it over anything else.
* The correct way for a "dotnet" NuGet package to be written (like all the System.* NuGet packages) is to explicitly list out their dependencies
* Maybe Xamarin Studio hasn't updated to consume "dotnet" TFMs yet (???) I don't know where exactly it stands.

Okay, thanks. The fault is probably with Xamarin here. It sucks because Xamarin ultimately ends up producing a different packages.config than Visual Studio does as a result. It seems like its a tough time to be developing in .NET land right now with all of these major shifts happening and nothing is quite settled yet.

raminasi
Jan 25, 2005

a last drink with no ice

Mr. Crow posted:

I'm getting a really bizarre log4net issue, I'm wondering if anyone has any ideas. Basically, when the (WPF) application loads up, it log4net loads its configuration context from the application config file correctly as expected; then at some point its configuration is switched to an entirely different applications configuration (Box Sync, in this case). Somehow Box Sync starts hijacking the log4net logs and my applications logging is getting dumped into a Box Sync log.

The hell?

I have no idea what's causing that, but I've had my own haunted-software experience with log4net that I never could resolve. Something about that library just ain't right.

Inverness
Feb 4, 2009

Fully configurable personal assistant.
I decided to create a modern project.json and dotnet platform PCL for a little project I was working on to familiarize myself with the technology, but I've encountered an annoying problem.

It depends on the latest beta Antlr4.Runtime NuGet package. Parser generation is done beforehand and not part of the actual build process, I just need the runtime.

The problem is the Antlr4.Runtime assembly, or anything else it might depend on, is not being copied to the output directory either when building the library or when building the normal console app that I've been using to test the library. Only the library DLL itself is copied.

Does this have something to do with the console test app not also using the new project.json or something?

Fake Edit:

Well I decided to give it a shot again right before submitting this post. I had thought my earlier attempts to add the project.json file to the console project failed, but it seems you need to reload the project to get that to be recognized. Doing this has solved my issue.

It seems like there is too little documentation about this whole thing and that it's all fragmented. I just solved another problem where the console test project could not find System.dll for some reason. I think it was caused by the Microsoft.NETCore.Portable.Compatibility dependency in the PCL that I just removed. :iiam: Googling reveals NuGet was likely at fault somehow.

Also apparently AssemblyBuilder.Save() is gone? I moved to having the non-portable test app provide an interface.

invision
Mar 2, 2009

I DIDN'T GET ENOUGH RAPE LAST TIME, MAY I HAVE SOME MORE?
I'm using SslStream to connect to a 'webserver'. I can't use httpclient/webclient/basically any library because of weird HTTP header stuff.

The 'server' basically just throws data at the client willy-nilly. The data is basically (customHTTPheader+/r/n/r/n+<message><bunchofstuff></bunchofstuff></message>+/r/n/r/n).

I need to figure out how to take the code that I'm currently using below, make it loop as long as the user has the connection up, and to have it take everything between <message> and </message> then send it to a parser in the background.
I've spent like 3 days on it and I absolutely cannot figure it out.

code:
 static string ReadAlarms(SslStream sslStream)
        {
            Console.WriteLine("in ReadAlarms");

            byte[] buffer = new byte[15000]; //wow look @ that buffer size.  
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            sslStream.ReadTimeout = 10000; //this is 3 seconds
            try
            {
                do
                {

                    bytes = sslStream.Read(buffer, 0, buffer.Length);
                    Decoder decoder = Encoding.UTF8.GetDecoder();
                    char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                    decoder.GetChars(buffer, 0, bytes, chars, 0);
                    messageData.Append(chars);
                    

                } while (bytes != 0);
            }

            catch (Exception)
            {
                Console.WriteLine("Incoming data stream empty, dumping buffer to parser.");
                return messageData.ToString();
            }

            return messageData.ToString();



        }
I'm just *really* stuck on how to pass the data back and forth between this and another class without screwing up the stream reading.

Mr Shiny Pants
Nov 12, 2012

invision posted:

I'm using SslStream to connect to a 'webserver'. I can't use httpclient/webclient/basically any library because of weird HTTP header stuff.

The 'server' basically just throws data at the client willy-nilly. The data is basically (customHTTPheader+/r/n/r/n+<message><bunchofstuff></bunchofstuff></message>+/r/n/r/n).

I need to figure out how to take the code that I'm currently using below, make it loop as long as the user has the connection up, and to have it take everything between <message> and </message> then send it to a parser in the background.
I've spent like 3 days on it and I absolutely cannot figure it out.

code:
 static string ReadAlarms(SslStream sslStream)
        {
            Console.WriteLine("in ReadAlarms");

            byte[] buffer = new byte[15000]; //wow look @ that buffer size.  
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            sslStream.ReadTimeout = 10000; //this is 3 seconds
            try
            {
                do
                {

                    bytes = sslStream.Read(buffer, 0, buffer.Length);
                    Decoder decoder = Encoding.UTF8.GetDecoder();
                    char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                    decoder.GetChars(buffer, 0, bytes, chars, 0);
                    messageData.Append(chars);
                    

                } while (bytes != 0);
            }

            catch (Exception)
            {
                Console.WriteLine("Incoming data stream empty, dumping buffer to parser.");
                return messageData.ToString();
            }

            return messageData.ToString();



        }
I'm just *really* stuck on how to pass the data back and forth between this and another class without screwing up the stream reading.

Kick the processing of to a seperate thread? That way the reading can still be done on the original thread.

Inverness
Feb 4, 2009

Fully configurable personal assistant.
With modern PCL's is there any reason to use the Microsoft.NETCore and Microsoft.NETCore.Portable.Compatibility packages instead of referencing your required dependencies individually?

Finally, a question on the dotnet imports section in the project.json file. The documentation only says it will add the appropriate import statement based on your targets, but I don't actually understand what it means in regards to your references to non-dotnet packages. What is it doing when I build?

invision
Mar 2, 2009

I DIDN'T GET ENOUGH RAPE LAST TIME, MAY I HAVE SOME MORE?

Mr Shiny Pants posted:

Kick the processing of to a seperate thread? That way the reading can still be done on the original thread.

How do I get the data out of it without stopping to send it somewhere?

Inverness
Feb 4, 2009

Fully configurable personal assistant.

invision posted:

How do I get the data out of it without stopping to send it somewhere?
I'm not really sure what you mean here. Could you be more specific? What issue do you have with the suggestion to use a second thread?

amotea
Mar 23, 2008
Grimey Drawer
The classic way is to use a thread-safe queue-like data structure to store the incoming data to for processing (producer). Another thread can then take items from the queue to process whenever he wants (consumer).

In modern C# there are more ways to go about this, but it should give you an idea of how multi-threaded stuff works. (also google producer-consumer problem)

ljw1004
Jan 18, 2005

rum

Inverness posted:

With modern PCL's is there any reason to use the Microsoft.NETCore and Microsoft.NETCore.Portable.Compatibility packages instead of referencing your required dependencies individually?

Finally, a question on the dotnet imports section in the project.json file. The documentation only says it will add the appropriate import statement based on your targets, but I don't actually understand what it means in regards to your references to non-dotnet packages. What is it doing when I build?

For your first question about Microsoft.NETCore nuget package, I'd never even heard of it, but I sent an email to the folks who (presumably) are in charge of it.

For the imports section, I haven't found proper documentation, but here's the story. Imagine you're writing a PCL which targets .NET46 and UWP. Your PCL will have a project.json and claim to be "dotnet". Morally it's entirely reasonable for your project to be able to reference a NuGet package that someone else wrote which claims to support e.g. "portable-net45+netcore". But the NuGet system has no way of knowing this. So the imports section is an escape hatch. It says "for the purpose of referencing other NuGets, in addition to allowing me to reference the things that I'm allowed to reference by virtue of me being 'dotnet', please also allow me to reference things that I'd be able to under my imports clause."

At least I think that's the story. If that answer makes sense and agrees with what you're observing, good! If it's not, then I'll ping the dev lead in charge and ask for more clarification.

ljw1004
Jan 18, 2005

rum

invision posted:

I'm just *really* stuck on how to pass the data back and forth between this and another class without screwing up the stream reading.

I think you only need to pass the data "forth" to its reader (not back and forth). Also, this scenario sounds like it's IO-bound. So a background thread will work, but seems a bit odd.

Conceptually what you have is an "async sequence" of messages that get produced by your ssl-stream-consuming function, and which get consumed by some other part of your code.

One way to do async sequences is in a "reactive" style using RX (Reactive Extensions for .NET). Personally, I prefer async/await. One async/await technique is to have a long-running async method which reads from the SslStream and sticks them into a TPL BufferBlock, from where they can be consumed by the rest of the code. But the way I'd strongly gravitate towards is something like an IAsyncEnumerable. That type isn't part of the framework itself (although it is part of RX), so in its absence I'd sort of code it up manually like this:

code:
// CONSUMER CODE

var messageReader = new MessageReader(sslStream);
while (await messageReader.MoveNextAsync())
{
    var msg = messageReader.Current;
    // Do with this string whatever you'd do...
    // If your work is CPU-bound and you're a UI app,
    // then you could use Task.Run to parse it on a background thread
    // But if it's not CPU-bound, or if you're a server app, then
    // there's no point using a background thread to process
    // the message.
}


// PRODUCER CODE
class MessageReader
{
    private StreamReader reader;

    public MessageReader(SslStream sslStream)
    {
        reader = new StreamReader(sslStream);
    }

    private string _current;
    public string Current => "a";

    public async Task<bool> MoveNextAsync()
    {
        var sb = new StringBuilder();
        string s;

        // First, gobble up any empty lines
        while (true)
        {
            s = await reader.ReadLineAsync();
            if (s == null) return false;
            if (!string.IsNullOrWhiteSpace(s)) break;
        }

        // the next line must start with <message>
        if (!s.StartsWith("<message>")) throw new IOException("malformed response from server");
        s = s.Substring(9);

        // keep reading until we get to a </message>
        while (!s.EndsWith("</message>"))
        {
            sb.AppendLine(s);
            s = await reader.ReadLineAsync();
            if (s == null) return false;
        }
        s = s.Substring(0, s.Length - 10);
        sb.AppendLine(s);

        _current = sb.ToString();
        return true;
    }
}
The C# team is considering adding something like IAsyncEnumerable to C#7. If we do, then the code would be more like this:
code:
// CONSUMER
foreach (await var msg in new MessageReader(sslStream))
{
   // do with this string whatever you'd do
}


// PRODUCER
static async IAsyncEnumerable<string> GetMessagesAsync(SslStream sslStream)
{
    var reader = new StreamReader(sslStream);
    while (true)
    {
        var sb = new StringBuilder();
        string s;

        // First, gobble up any empty lines
        while (true)
        {
            s = await reader.ReadLineAsync();
            if (s == null) yield break;
            if (!string.IsNullOrWhiteSpace(s)) break;
        }

        if (!s.StartsWith("<message>")) throw new IOException("malformed response from server");
        s = s.Substring(9);

        // keep reading until we get to a </message>
        while (!s.EndsWith("</message>"))
        {
            sb.AppendLine(s);
            s = await reader.ReadLineAsync();
            if (s == null) yield break;
        }
        s = s.Substring(0, s.Length - 10);
        sb.AppendLine(s);
        yield return sb.ToString();
    }
}
PS. All this post is speculative and untested. I've never used SslStream myself. The code I wrote to parse it into <message> blocks is obviously a bit goofy, and will only work if the string </message> never appears inside a message itself.

Inverness
Feb 4, 2009

Fully configurable personal assistant.

ljw1004 posted:

For your first question about Microsoft.NETCore nuget package, I'd never even heard of it, but I sent an email to the folks who (presumably) are in charge of it.
It's added by default when you create a modern PCL project. Through its dependencies it adds a standard set of packages for .NET Core platforms: http://www.nuget.org/packages/Microsoft.NETCore/5.0.1-beta-23516. I suppose it would be comparable to the assemblies that are referenced by default when you make a desktop library project.

It seems pretty convenient, but the thing is it just seems like it would be a better idea to only reference what you actually need if your library will not be using a lot.

quote:

For the imports section, I haven't found proper documentation, but here's the story. Imagine you're writing a PCL which targets .NET46 and UWP. Your PCL will have a project.json and claim to be "dotnet". Morally it's entirely reasonable for your project to be able to reference a NuGet package that someone else wrote which claims to support e.g. "portable-net45+netcore". But the NuGet system has no way of knowing this. So the imports section is an escape hatch. It says "for the purpose of referencing other NuGets, in addition to allowing me to reference the things that I'm allowed to reference by virtue of me being 'dotnet', please also allow me to reference things that I'd be able to under my imports clause."

At least I think that's the story. If that answer makes sense and agrees with what you're observing, good! If it's not, then I'll ping the dev lead in charge and ask for more clarification.
My question was more directed at the bit about "please also allow me to reference things that I'd be able to under my imports clause." I'm relatively new to the PCL world so I don't know how this works.

My guess is that you can reference anything that is less than or equal to the surface area your PCL covers?

EssOEss
Oct 23, 2006
128-bit approved
I saw Microsoft.NETCore as a convenient way to say "I want .NET Core and I don't care about the details". This would be rather convenient, as I actually don't fancy manually picking and choosing 10 different System.Whatever packages and maintaining their versions. Just being able to say "Give me the entire .NET Core API surface and shut up" would be awesome.

Unfortunately, it does not work! At least, it does not work if you reference from a .NET Framework 4.6 app a .NET Core NuGet package that depends on Microsoft.NETCore - you get some error that some library Microsoft.NETCore depends on does not support .NET Framework 4.6.

This new NuGet generation is really full of black robes and mysticism - totally unintelligible to me. The only learning method available is trial and error.

Inverness
Feb 4, 2009

Fully configurable personal assistant.

EssOEss posted:

I saw Microsoft.NETCore as a convenient way to say "I want .NET Core and I don't care about the details". This would be rather convenient, as I actually don't fancy manually picking and choosing 10 different System.Whatever packages and maintaining their versions. Just being able to say "Give me the entire .NET Core API surface and shut up" would be awesome.

Unfortunately, it does not work! At least, it does not work if you reference from a .NET Framework 4.6 app a .NET Core NuGet package that depends on Microsoft.NETCore - you get some error that some library Microsoft.NETCore depends on does not support .NET Framework 4.6.

This new NuGet generation is really full of black robes and mysticism - totally unintelligible to me. The only learning method available is trial and error.
Are you using project.json instead of packages.config in that 4.6 app? AFAIK you need to use the new system to properly reference things using the new system.

I've actually just run into a problem where two packages in the project.json dependencies use two different versions of the same assembly. This wasn't a problem before since I could just ensure my project referenced the newer version, but now references are handled by nuget and the auto generate binding redirects option for the project doesn't help.

EssOEss
Oct 23, 2006
128-bit approved
I am using packages.json, if I remember it right. I know I tried both ways and both resulted in the same situation.

Inverness
Feb 4, 2009

Fully configurable personal assistant.

EssOEss posted:

I am using packages.json, if I remember it right. I know I tried both ways and both resulted in the same situation.
Package.json is for NPM, not NuGet.

When you use a project.json file with a normal .NET 4.6 app or library you also need to declare the net46 framework and win runtime. Did you do that? If you don't you get build errors that tell you to do it.

Here is the project.json file for a WPF app I just converted from packages.config.
code:
{
    "dependencies": {
        "Extended.Wpf.Toolkit": "2.5.0",
        "JetBrains.Annotations": "10.0.0",
        "Newtonsoft.Json": "7.0.1",
        "Newtonsoft.Json.Schema": "1.0.11",
        "Prism.Core": "6.1.0",
        "Prism.Wpf": "6.1.0",
        "Prism.Mef": "6.1.0",
        "Ookii.Dialogs": "1.0.0"
    },
    "frameworks": {
        "net46": { }
    },
    "runtimes": {
        "win": { }
    }
}
Also make sure you reload the project after adding the project.json file to an existing project.

I just went and tested creating a new portable library that depends on Microsoft.NETCore and I had no issue referencing the project from that WPF app.

Edit:

quote:

This new NuGet generation is really full of black robes and mysticism - totally unintelligible to me. The only learning method available is trial and error.
Yes, there seems to be a lack of comprehensive or centralized documentation. I spent half an hour earlier trying to hunt down the documentation for the include and exclude options for project.json dependencies because I could not remember from where I had read it the first time.

Inverness fucked around with this message at 21:49 on Dec 14, 2015

chippy
Aug 16, 2006

OK I DON'T GET IT
I've written a class (a simple Json poster) that uses a HttpClient to make its requests. It just uses one instance initialised in the constructor rather than creating a new one for each requests. Should I:

- Implement IDisposable on the Json poster and have it dispose the HttpClient?
- Implement a finalizer on the Json poster which calls dispose on the HttpClient?
- Neither?

Similarly, if I choose to implement IDisposable, and have an app (WinForms) that uses a single instance of the json poster for it's lifetime, should that app have a destructor or something, or can I just rely on everything being cleaned up when it's finished? Should I override OnClose or Finalize on the form, or something like that?

chippy fucked around with this message at 10:18 on Dec 16, 2015

Mongolian Queef
May 6, 2004

chippy posted:

I've written a class (a simple Json poster) that uses a HttpClient to make its requests. It just uses one instance initialised in the constructor rather than creating a new one for each requests. Should I:

- Implement IDisposable on the Json poster and have it dispose the HttpClient
- Implement a finalizer on the Jspon poster which calls dispose on the HttpClient?
- Neither?

Similarly, if I choose to implement IDisposable, and have an app (WinForms) that uses a single instance of the json poster for it's lifetime, should that app have a destructor or something, or can I just rely on everything being cleaned up when it's finished? Should I override OnClose or Finalize on the form, or something like that?

I would implement IDisposable on the Json poster and make sure that it is disposed in OnClosing of the Form using it.

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

chippy posted:

- Implement a finalizer on the Json poster which calls dispose on the HttpClient?
People much smarter than me have laid out some good arguments that if you have to ask "should I implement a finalizer", the answer is almost certainly no.

IDisposable is great. Implement that all over the place if you think it might possibly make sense. Finalizers are strange and complicated and only useful in certain specific cases that you probably aren't ever going to run into.

Inverness
Feb 4, 2009

Fully configurable personal assistant.

Jethro posted:

People much smarter than me have laid out some good arguments that if you have to ask "should I implement a finalizer", the answer is almost certainly no.

IDisposable is great. Implement that all over the place if you think it might possibly make sense. Finalizers are strange and complicated and only useful in certain specific cases that you probably aren't ever going to run into.
The disposable pattern is tied at the hip with finalizers, because the original intent for IDisposable is to allow you to explicitly free unmanaged resources. Calling dispose from a finalizer is the closest you can get to guaranteeing that your unmanaged resources will be disposed at some point.

I can't see a case where you would reasonably implement IDisposable but not include the pattern to call from a finalizer.

Just to clarify the pattern I mean:
code:
    public abstract class DisposableObject : IDisposable
    {
        ~DisposableObject()
        {
            Dispose(false);
        }

        public bool IsDisposed { get; private set; }

        public void Dispose()
        {
            if (IsDisposed)
                return;
            Dispose(true);
            GC.SuppressFinalize(this);
            IsDisposed = true;
        }

        protected virtual void Dispose(bool disposing)
        {
        }

        protected void VerifyNotDisposed()
        {
            if (IsDisposed)
                ThrowObjectDisposed();
        }

        private void ThrowObjectDisposed()
        {
            throw new ObjectDisposedException(GetType().Name);
        }
    }

    public class MyObjectWithUnmanagedResources : DisposableObject
    {
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose managed resources
            }

            // dispose unmanaged resources
        }
    }
Implementing it this way gives you the option to dispose your unmanaged resources explicitly or on finalization with a boolean indicating whether Dispose() was explicit.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Inverness posted:

The disposable pattern is tied at the hip with finalizers, because the original intent for IDisposable is to allow you to explicitly free unmanaged resources. Calling dispose from a finalizer is the closest you can get to guaranteeing that your unmanaged resources will be disposed at some point.

I can't see a case where you would reasonably implement IDisposable but not include the pattern to call from a finalizer.

...

Implementing it this way gives you the option to dispose your unmanaged resources explicitly or on finalization with a boolean indicating whether Dispose() was explicit.

In which case, you should probably be using SafeHandle.

Bognar fucked around with this message at 16:40 on Dec 16, 2015

chippy
Aug 16, 2006

OK I DON'T GET IT
Thanks for the info. From what I'm reading, though, it seems like the full-on disposable pattern (with the bool parameter and the finalizer) is only necessary if you are using unmanaged resources in your class - if you are just using managed objects that are themselves disposable, it's enough to just do a simple dispose() method that calls dispose() on those objects. Does this sound correct, or does anyone have a counter-argument to this?

The reason being:

code:
public class MyObjectWithUnmanagedResources : DisposableObject
    {
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose managed resources
            }

            // dispose unmanaged resources
        }
    }
If you don't have any unmanaged resources to dispose, then Dispose(bool disposing) doesn't actually end up doing anything when called from the finalizer (because disposing is false).

I'm presuming that in my case, HttpClient doesn't count as a unmanaged resource, because it handles its unmanaged resources itself when you call dispose on it?

chippy fucked around with this message at 17:26 on Dec 16, 2015

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

chippy posted:

Thanks for the info. From what I'm reading, though, it seems like the full-on disposable pattern (with the bool parameter and the finalizer) is only necessary if you are using unmanaged resources in your class - if you are just using managed objects that are themselves disposable, it's enough to just do a simple dispose() method that calls dispose() on those objects. Does this sound correct, or does anyone have a counter-argument to this?

Yep, that's correct. If your class just contains references to other Disposable objects (and you assume that those Disposable objects correctly implement Disposable/Finalizers) then you have no need for a finalizer.

chippy
Aug 16, 2006

OK I DON'T GET IT
Nice one, thanks.

crashdome
Jun 28, 2011
I'm really glad this conversation got started because I just encountered this last night. I wrote a quick UWP app to test authentication methods against a web api using Wireshark. There is no documentation so I used an Android app and Wireshark to gather what my requests need to look like and then started writing.

I have a single form with button that calls a single class in my test solution.

C# code:
        private async void button_Click(object sender, RoutedEventArgs e)
        {
            Test t = new Test();

            var result = await t.TestMethod();
        }
Here is the Test Class. Bear in mind I was only using this to allow me to capture through Wireshark. The program is only for tweaking what I need until I got it right.

C# code:
    internal class Test
    {
        public async Task<bool> TestMethod()
        {
            var username = "user@email.com";
            var password = "password";
            var url = "mysite.com";
            var port = "80";

            var filter = new HttpBaseProtocolFilter();
            filter.AllowUI = false;
            
            var client = new HttpClient(filter);
            try
            {
                client.DefaultRequestHeaders.Accept.Add(new 
                    HttpMediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Basic",
                    Convert.ToBase64String(Encoding.ASCII.GetBytes(
                    string.Format("{0}:{1}", username, password))));
                client.DefaultRequestHeaders.UserAgent.Add(new 
                    HttpProductInfoHeaderValue("Some User Agent Text"));

                var response = await client.GetAsync(new 
                    Uri(string.Format("http://{0}:{1}/api/stuff.json",url, port)), 
                    HttpCompletionOption.ResponseContentRead);                
            }
            catch (System.Exception ex)
            {
                string error = ex.Message;
                return false;
            }
            finally
            {
                client.Dispose();
                filter.Dispose();
            }
            return true;
        }
    }
If I didn't call Dispose for those two items in the finally block, I had erratic behavior. For example, pausing and changing the username and password without the dispose on both the HttpClient and the HttpBaseProtocolFilter meant that subsequent calls would use the old username and password. I was hoping to get an Access Denied response when I altered them by one character but instead, I was getting a 200 response. Wireshark told me the actual response was 302 NOT CHANGED and inspecting the request showed the previous Authentication values - not the values I had just changed it to.

Calling Dispose fixed that problem. I want my app to be able to keep the HttpClient as long as the app is in use. When the user switches profiles or changes their username and password, I want to create a new HttpClient object and I want to get rid of the previous HttpClient object. During my test above (which creates one every click of the button) if I did not call dispose, I would have random and erratic behavior I did not expect.

Any thoughts?

e:tables

crashdome fucked around with this message at 19:47 on Dec 16, 2015

EssOEss
Oct 23, 2006
128-bit approved
I have noted random failures (of the "Generic COMException" kind with a meaningless "Invalid parameter" error code) after long-term use (thousands of requests) with both HttpClients (System.Net.HttpClient and whatever the other one was... Windows.Net.HttpClient maybe), though they were slightly different failure modes for each. I forget what my last bodge was but I possibly implemented some "recreate HttpClient and retry on exception" logic. Was unable to reproduce it on the day I felt like reporting it to Microsoft, so never did narrow it down to something straightforward in the end.

Note quite the same as yours but it really gives me the feeling there is something rotten in the network stack. I also found an issue where it simply hangs forever in some HttpClient calls (reported on Connect with repro; both HttpClients once again). Whatever is causing your funkiness, try to narrow it down and get fixed, for the good of all of us!

EssOEss fucked around with this message at 20:02 on Dec 16, 2015

crashdome
Jun 28, 2011
I might try and run this again tonight. Maybe I'll implement logging and try doing some dry runs of 100's+ of requests, switching parameters, run more, etc... It almost felt like there was some caching going on or under the hood somewhere it is reusing something I don't want it to. Dispose did seem to make it reliable for the few requests I did. It also makes sense to me. I understand an object will get cleared when its references are released but, for posterity calling Dispose should force it to clean up anything in the stack that a new HttpClient might want to use. AFAIK Windows.Web.Http is just ultimately a wrapper after all.

The thing that scared me the most was changing the username and password in the Authorization header and then it sent the old one. When a user switches profiles in my app, I can't have that happen.

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

Inverness posted:

I can't see a case where you would reasonably implement IDisposable but not include the pattern to call from a finalizer.

Bognar posted:

If your class just contains references to other Disposable objects (and you assume that those Disposable objects correctly implement Disposable/Finalizers) then you have no need for a finalizer.

Ochowie
Nov 9, 2007

I've started playing around .NET Core and ASP.NET 5 on Linux and I've run into some issues/confusion. The thing I'm confused about the most is the difference between DNX and .NET Core (as executed by the dotnet command). I tried running the sample hello world application using just .NET Core (I think) on Ubuntu 15.04 and it failed because it couldn't find System.Console (which is a known issue). However, if I run the same setup using DNX it works without issue. So my question is, which framework is DNX using in the background? Is it it my Mono install or is it still using .NET Core but accessing it in a different way? It's also possible that I'm totally offbase with this. This is the project.json for reference:

code:
{
    "version": "1.0.0-*",
    "compilationOptions": {
        "emitEntryPoint": true
    },

    "dependencies": {
        "Microsoft.NETCore.Runtime": "1.0.1-beta-*",
        "System.IO": "4.0.11-beta-*",
        "System.Console": "4.0.0-beta-*",
        "System.Runtime": "4.0.21-beta-*"
    },

    "frameworks": {
        "dnxcore50": { }
    }
}

Adbot
ADBOT LOVES YOU

EssOEss
Oct 23, 2006
128-bit approved
The way I think about it is that .NET Core is a set of interfaces/APIs that are exposed by various products called CoreFX (often used with the DNX runtime; which... I think... is the same as CoreCLR) and the Base Class Library (often used with the .NET Framework runtime). To "run something with .NET Core" makes no sense to me - it is not a piece of software, though it is implemented by various pieces of software.

Just my two cents; I am not comfortable enough with the topic to be able to help you out any more or to really commit to this interpretation!

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply