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
raminasi
Jan 25, 2005

a last drink with no ice

Supersonic posted:

On the topic of WPF, I've been working on a larger WPF project with some other people, and one issue I've been running into is understanding Databinding. For example, consider the following view:
code:
<dx:LoadingDecorator
    x:Class="QDev.DataManagement.Client.Wpf.Views.CustomizableLoadingDecorator"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
    xmlns:local="clr-namespace:QDev.DataManagement.Client.Wpf.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="450"
    d:DesignWidth="800"
    SplashScreenDataContext="{Binding }">
        <dx:LoadingDecorator.SplashScreenTemplate>
            <DataTemplate>
                <dx:WaitIndicator Content="{Binding }" DeferedVisibility="True">
                    <dx:WaitIndicator.ContentTemplate>
                        <DataTemplate>
                        <TextBlock Text="{Binding SpinnerText}" />
                        </DataTemplate>
                    </dx:WaitIndicator.ContentTemplate>
                </dx:WaitIndicator>
            </DataTemplate>
        </dx:LoadingDecorator.SplashScreenTemplate>
</dx:LoadingDecorator>


The splash screen and data template both use {Binding} with nothing specified. Looking at example view files from MS documentation, they all seem to explicitly set this to something, eg:
code:
Background = "{Binding ElementName = comboBox, Path = SelectedItem.Content}">
How can I tell what is bound to what here?

Those things are just properties being set on the created Binding object, and you can check the documentation for each property to see what happens if it's unset. (For example, if Path is unset, it's equivalent to Path=..) You should also read the Binding declarations overview if you haven't yet.

Adbot
ADBOT LOVES YOU

Kyte
Nov 19, 2013

Never quacked for this
This is kinda overkill but what about making a self-hosted webapp. Then you can build the frontend with HTML, grab some JS library for dashboard widgets and plug everything together with ajax.

distortion park
Apr 25, 2011


Kyte posted:

This is kinda overkill but what about making a self-hosted webapp. Then you can build the frontend with HTML, grab some JS library for dashboard widgets and plug everything together with ajax.

Retool does this for you more or less. It's got lots of rough edges, but less than anything DIY will.

Seriously just use Retool or maybe airtable.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

insta posted:

The actual use-case is customers defining 'dashboards' for serial-connected devices. The devices will have different parameters that can be either read or written, and sometimes the 'write' needs to be an expression from the 'read'. The devices are not all the same, and each customer has a different use-case for the parameters they want to read or write.

Piling on here too. By chance, did they themselves mention "dashboard?" If so, I would call them out on that. Those are presentation layers for viewing data and all the interaction should be in messing with that view. There's a bunch of poo poo for that and you won't hear and angel sing for using any of them. However, as soon as interaction like those writes come into play, it is indeed another person's attempt to avoid programming that will eventually require programming anyways.

Toast Museum
Dec 3, 2005

30% Iron Chef
Am I missing something, or does GetFromJsonAsync preclude accessing response headers?

I'm consuming an API for which each method's rate-limit info (requests per interval allowed, remaining requests in this interval, and when this interval ends) is communicated via x-headers in the response. GetFromJsonAsync will throw an HttpRequestException if the request was unsuccessful, and it can tell me that the status code was 429 TooManyRequests, but the exception doesn't seem to include any response header data, so I can't say how long to wait before trying again.

So far, it seems like I'll have to switch to GetAsync plus ReadFromJsonAsync, but I'm open to being wrong about that!

No Pants
Dec 10, 2000

The new extension methods are for fairly simple scenarios. They're just calling HttpResponseMessage.EnsureSuccessStatusCode(), which only gives you the status code, so you're on the right track.

Mind, you can still use GetFromJsonAsync() and have retries based on response headers if you feel up to creating a custom retry policy using Polly.

No Pants fucked around with this message at 04:48 on Jan 6, 2022

Toast Museum
Dec 3, 2005

30% Iron Chef
What gets me is that PostAsJsonAsync and PutAsJsonAsync both return Task<HttpResponseMessage>, so in those cases I can get what I need from HttpResponseMessage.Headers.GetValues. It's just GetFromJsonAsync that seems to be the odd one out, returning Task<Object> instead.

At a glance, Polly seems like overkill for what I'm doing, but also like something I should probably get familiar with, so thanks for putting it back on my radar!

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer

Toast Museum posted:

What gets me is that PostAsJsonAsync and PutAsJsonAsync both return Task<HttpResponseMessage>, so in those cases I can get what I need from HttpResponseMessage.Headers.GetValues. It's just GetFromJsonAsync that seems to be the odd one out, returning Task<Object> instead.

At a glance, Polly seems like overkill for what I'm doing, but also like something I should probably get familiar with, so thanks for putting it back on my radar!

I can sort of see the logic of it. With Get you're always going to be interested in the response body, so it's convenient for the response to simply be the deserialized object. With Put and Post you often only care about the status, so it makes less sense to automatically deserialize the response. The "AsJson" in the Put and Post refers to the input rather than the output.

But yeah, if you need to inspect the headers of a Get request you'll need to use GetAsync directly.

Toast Museum
Dec 3, 2005

30% Iron Chef

LOOK I AM A TURTLE posted:

I can sort of see the logic of it. With Get you're always going to be interested in the response body, so it's convenient for the response to simply be the deserialized object. With Put and Post you often only care about the status, so it makes less sense to automatically deserialize the response. The "AsJson" in the Put and Post refers to the input rather than the output.



Nah, that's reasonable, even if it's proving inconvenient at the moment. I certainly didn't mind the reduced boilerplate until now. It would be nice if the headers wound up in HttpRequestException.Data or something, though.

Mr Shiny Pants
Nov 12, 2012
I don't really like the HttpClient to be honest, and I like that I can just create a HttpWebRequest from scratch using the "obsolete" APIs.

Is there any reason I need to switch? I mean, System.Net is pretty bulletproof by now right?

Red Mike
Jul 11, 2011

Mr Shiny Pants posted:

I don't really like the HttpClient to be honest, and I like that I can just create a HttpWebRequest from scratch using the "obsolete" APIs.

Is there any reason I need to switch? I mean, System.Net is pretty bulletproof by now right?

If you want to build your own wrapper around it, to handle all connection pooling/error and timeout handling/disposal, there's no reason to switch. If you want those things, HttpClient is the only reliable built-in way to get them.

Additionally, if you're working with modern ASP.NET Core then HttpClient itself is well integrated so you can more easily grab instances of it as needed (tied to scope, etc).

Mr Shiny Pants
Nov 12, 2012

Red Mike posted:

If you want to build your own wrapper around it, to handle all connection pooling/error and timeout handling/disposal, there's no reason to switch. If you want those things, HttpClient is the only reliable built-in way to get them.

Additionally, if you're working with modern ASP.NET Core then HttpClient itself is well integrated so you can more easily grab instances of it as needed (tied to scope, etc).

I get that, and some things it does well (Forms and the like) but for just getting a reply from an endpoint I really like just being able to create an async method from scratch and know where all the stuff is getting used.

I really like being able to do:

code:
let getAudio text = 
    async {
        let request = System.Net.WebRequest.Create(buildUrl(text)) :?> HttpWebRequest
        request.Method <- "GET"
        let! response = Async.FromBeginEnd(request.BeginGetResponse, request.EndGetResponse)
        return response.GetResponseStream()
    }

Red Mike
Jul 11, 2011

Mr Shiny Pants posted:

I get that, and some things it does well (Forms and the like) but for just getting a reply from an endpoint I really like just being able to create an async method from scratch and know where all the stuff is getting used.

I really like being able to do:

code:
let getAudio text = 
    async {
        let request = System.Net.WebRequest.Create(buildUrl(text)) :?> HttpWebRequest
        request.Method <- "GET"
        let! response = Async.FromBeginEnd(request.BeginGetResponse, request.EndGetResponse)
        return response.GetResponseStream()
    }

So is there a difference between that and this (C# obviously):

code:
var task = Task.Run(async () => {
  var httpClient = new HttpClient(); //or grab it from an IHttpClientFactory
  //the underlying pools are shared so instantiation isn't that expensive
  //however a shared member should still be used for certain quirks (a timeout cancelling subsequent requests on the same URL)
  using (var request = new HttpRequestMessage(HttpMethod.Get, "/my/url"))
  {
    //here you could add request body
    //request.Content = new StringContent(...)
    string responseBody;
    using (var response = await _httpClient.SendAsync(request))
    {
      if (response.StatusCode == HttpStatusCode.OK) {
        responseBody = await response.Content.ReadAsStringAsync();
      } else {
        //do whatever, throw, etc
      }
    }
    return responseBody;
  }
});
//await it, or .GetResult it or whatever
If you mean that this code abstracts away some of the logic/resource usage (e.g. pooling connections, handling timeouts, etc), then yeah that's the trade-off. If you mean something else, I'm not seeing a difference between the two.

e: Also to be clear, I think some of the choices in HttpClient are pretty daft. The timeout handling especially is finnicky and can catch you by surprise in certain situations (hitting the same URL/path with different data for different operations, and some operations being expected to sometimes time out while others don't - this can cause those others to also act as if they timed out if they were pending while the first one times out - the workaround is to always pass in a CancellationToken as appropriate instead of letting it create one against the URL/path/handler)

But I still prefer it to the raw request classes whenever I actually need to do HTTP because it's a low enough level construct that I just care about the HTTP request happening, and any fixes I want to this logic need to apply to all outgoing HTTP requests anyway. Basically, my job is to solve problems, not to write perfect code.

Red Mike fucked around with this message at 11:30 on Jan 7, 2022

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I have a situation where I'm creating two HashSets with contents that equal each other, although the contents themselves are unique instance between each other (so they're not literally the same object, but Equals() is implemented). When try to use Equals to check both HashSets, I get false, but SetEquals() is true. Should I normally be using SetEquals here?

Edit: In this particular case it's for asserting in my unit testing that the set I produce in my test equals a reference for what the set should contain.

Kyte
Nov 19, 2013

Never quacked for this
According to the docs, HashSet.Equals compares the object identities (it just inherits from Object). SetEquals compares the contents. You clearly want the latter.
(Element equality is checked using IEqualityComparer btw)

Boz0r
Sep 7, 2006
The Rocketship in action.
Some people from my work have a boner for MS Power Apps, but I hate working with them, and they always become a pain to maintain beyond a PoC stage. Are there any good alternatives in C# frameworks that can match the PoC speed, but also be robust, where I can still control the code?

Just-In-Timeberlake
Aug 18, 2003
Any ASP.NET experts here? Particularly with the web.config and IIS10?

We have a custom error page to handle any errors, and we need that initial form data to go along for the ride.

This works when deployed to our old Server 2012 instance on AWS, and run on localhost via Visual Studio and IISExpress on a Server 2019 machine:

code:
	<customErrors defaultRedirect="~/errors/errorHandler.aspx" mode="On" redirectMode="ResponseRewrite">
        </customErrors>
However, when deployed to an AWS Server 2019/IIS10 instance, while it does go to the error handler page, the form data is not being transferred. I've verified this by using Response.Write(Request.Form()), just blank.

I feel like I'm missing some setting in IIS10, but Googling isn't bringing anything up.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Boz0r posted:

Some people from my work have a boner for MS Power Apps, but I hate working with them, and they always become a pain to maintain beyond a PoC stage. Are there any good alternatives in C# frameworks that can match the PoC speed, but also be robust, where I can still control the code?

Ahh the never ending cycle.

Developers are expensive!
Let's use a tool to let business users develop solutions without developers!
This thing we built is too complex and hard to maintain! We need developers!
Everyone claims to have learned their lesson and to just let developers write software.
GOTO START

Polio Vax Scene
Apr 5, 2009



Writing the code is the least important part of writing code

Kyte
Nov 19, 2013

Never quacked for this

Boz0r posted:

Some people from my work have a boner for MS Power Apps, but I hate working with them, and they always become a pain to maintain beyond a PoC stage. Are there any good alternatives in C# frameworks that can match the PoC speed, but also be robust, where I can still control the code?

Isn't that what the azure functions integration stuff is for?

fuf
Sep 12, 2004

haha
Can anyone help me write this LINQ statement or tell me some keywords to google?

I have a List<Video> and each Video object has its own List<Tag>.

I want to select all the Tags that the list of Videos has in common.

So like:
code:
List<Video> videos;
List<Tag> allTags;
List<Tag> commonTags;
commonTags = allTags.Where(???????)

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You're looking for the intersection of all the sets of tags.

You could do something like:
code:
var tags = new HashSet<Tag>(videos[0].tags);
foreach (Video v in videos.Skip(1)) {
  tags.IntersectWith(v.tags);
}

Airflamer
Jan 21, 2012

wow that story was super amazingly awesome, im not even joking right now

Grimey Drawer

fuf posted:

Can anyone help me write this LINQ statement or tell me some keywords to google?

I have a List<Video> and each Video object has its own List<Tag>.

I want to select all the Tags that the list of Videos has in common.

So like:
code:
List<Video> videos;
List<Tag> allTags;
List<Tag> commonTags;
commonTags = allTags.Where(???????)

Probably not the best solution

code:
var commonTags = allTags
            .GroupBy(x => x.TagId)
            .Where(x => x.Count() == videos.Count)
            .Select(X => X.First());

mystes
May 31, 2006

Jabor posted:

You're looking for the intersection of all the sets of tags.

You could do something like:
code:
var tags = new HashSet<Tag>(videos[0].tags);
foreach (Video v in videos.Skip(1)) {
  tags.IntersectWith(v.tags);
}
If OP wants to do this in a linq (functional) style they could do it as a reduce (fold).

Chrungka
Jan 27, 2015
How about this?
code:
var commonTags = videos
    .Select(x => x.Tags)
    .Aggregate<IEnumerable<string>>((aggregate, x) => aggregate.Intersect(x));
Here is an dotnetfiddle example: https://dotnetfiddle.net/GWl1Pi

Chrungka fucked around with this message at 16:17 on Jan 22, 2022

fuf
Sep 12, 2004

haha
Thanks a lot guys, much appreciated

Jabor posted:

You're looking for the intersection of all the sets of tags.

You could do something like:
code:
var tags = new HashSet<Tag>(videos[0].tags);
foreach (Video v in videos.Skip(1)) {
  tags.IntersectWith(v.tags);
}

This works fine, but I can't claim to understand exactly what's going on. I need to do a LINQ course or something.

Mata
Dec 23, 2003

fuf posted:

Thanks a lot guys, much appreciated

This works fine, but I can't claim to understand exactly what's going on. I need to do a LINQ course or something.

The only Linq in there is the Skip(1) which you probably don't need a whole course for, but understanding the HashSet data structure and set operations more generally is good.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

fuf posted:

Thanks a lot guys, much appreciated

This works fine, but I can't claim to understand exactly what's going on. I need to do a LINQ course or something.

The first line is copying the tags of the first video. (This will cause an exception if the list of videos is empty.)

The loop is over the set of videos. At each loop iteration, the set of tags is updated to be the intersection between the current set, and the tags of the current video. Once all videos have been looped through, you are left with only the tags that are found on every video in the list.

The .Skip(1) skips over the first video. It doesn't make a difference to the final result, it just isn't necessary to perform that intersection operation, because by definition it's going to make no difference (the set of tags has been initialised to the tags of the first video already; intersection of a set with itself yields the same set again).

insta
Jan 28, 2009
Monthly reminder that if you are ever doing a . Contains() operation on a collection, you probably want a HashSet unless you know for sure you want a List. I see this way too often and it's a huge performance drain. *Especially* if you are doing something as a "if not Contains, do an operation and add it to the list and loop" thing.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Kyte posted:

According to the docs, HashSet.Equals compares the object identities (it just inherits from Object). SetEquals compares the contents. You clearly want the latter.
(Element equality is checked using IEqualityComparer btw)

I had seen your response yesterday but I had to double check something today. I also have a similar with where I use a List<> and I thought Equals() was comparing contents there. But I checked it today and bam, I am manually comparing contents. So that is what I get for 2AM coding.

insta
Jan 28, 2009
Copy both lists to HashSets and subtract them from each other. If there's any elements left, they don't match. This will be way faster than whatever you're doing.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

insta posted:

Copy both lists to HashSets and subtract them from each other. If there's any elements left, they don't match. This will be way faster than whatever you're doing.

Order matters for the list comparison. I just thought for some reason that List.Equals would check contents (which it doesn't and I wasn't even using) so HashSet.Equals should also check contents. It was a real brain fart all around.

SirViver
Oct 22, 2008

Rocko Bonaparte posted:

Order matters for the list comparison.
For that you can just use the .SequenceEqual() LINQ extension. A small optimization for that would be to additionally compare the list counts before comparing the sequence - the extension method doesn't check for that kind of shortcut IIRC.

No Pants
Dec 10, 2000

Rocko Bonaparte posted:

I had seen your response yesterday but I had to double check something today. I also have a similar with where I use a List<> and I thought Equals() was comparing contents there. But I checked it today and bam, I am manually comparing contents. So that is what I get for 2AM coding.

if this is still for unit testing, testing frameworks usually have an equality assertion method that compares the contents of collections.

brap
Aug 23, 2004

Grimey Drawer

SirViver posted:

For that you can just use the .SequenceEqual() LINQ extension. A small optimization for that would be to additionally compare the list counts before comparing the sequence - the extension method doesn't check for that kind of shortcut IIRC.

SequenceEqual checks the lengths, at least in recent .NETs.
https://github.com/dotnet/runtime/b...nceEqual.cs#L32

insta
Jan 28, 2009

Rocko Bonaparte posted:

Order matters for the list comparison. I just thought for some reason that List.Equals would check contents (which it doesn't and I wasn't even using) so HashSet.Equals should also check contents. It was a real brain fart all around.

If order matters, that should be part of the object in the HashSet, and the equality and GetHashCode methods should be aware of it :colbert:

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
Guys, I brought up list because I had incorrectly thought it deep compared and was surprised HashSet.Equals did not. I did not intend to literally compare a List and a HashSet. I was just incorrectly referencing behavior from other collections in the .NET framework.

LongSack
Jan 17, 2003

Question about using DI in a desktop application.

My Ledger application was originally written using the Locator pattern. I've since been informed that some (many?) people consider the Locator to be an anti-pattern because it obfuscates the dependencies (i.e., you can't just look at the constructor and see the dependencies). Point taken.

So I'm rewriting the application into .NET 6 / C# 10 using dependency injection (not because of the Locator, there are other reasons to rewrite and I'm just taking advantage of them to remove the Locator as well). I'm just getting started on the WPF client, and I've got this so far:
C# code:
public partial class App : Application
{
    public IServiceProvider ServiceProvider { get; }

    public App()
    {
        var services = new ServiceCollection();
        ConfigureServices(services);
        ServiceProvider = services.BuildServiceProvider();
    }

    private void ApplicationStartup(object sender, StartupEventArgs e)
    {
        var mainViewModel = ServiceProvider.GetRequiredService<MainViewModel>();
        var mainWindow = new MainWindow
        {
            DataContext = mainViewModel
        };
        mainWindow.Show();
    }

    private static void ConfigureServices(IServiceCollection services)
    {
			.
			.
			.
    }
}
This works well now, because right now the MainViewModel is the only view model (I'm just starting the rewrite).

However, once the app is complete, there will be an additional 20 or so view models, which are all used with windows called from the MainViewModel. This means that - at the end - to instantiate the MainViewModel, I'll also have to instantiate all of the other view models with their respective dependencies, essentially instantiating the entire application. This is not good. My data access classes are designed to be transient.

So I'm thinking, to work around this, that I'll use a factory class to instantiate the view models, something like this:
C# code:
public class ViewModelFactory<T>

    public T? Create()
    {
        var app = Application.Current as App;
        return app?.ServiceProvider.GetRequiredService<T>();
    }
}
This still hides the dependencies of the MainViewModel, but the dependencies of the other view models are in their constructors, so it's not as bad as a Locator.

So, is this a terrible idea? Is there a better way?

TIA

distortion park
Apr 25, 2011


LongSack posted:

This means that - at the end - to instantiate the MainViewModel, I'll also have to instantiate all of the other view models with their respective dependencies, essentially instantiating the entire application. This is not good. My data access classes are designed to be transient.

Instead of depending directly on those transient view models, you could depend on a view model factory (or one per VM depending on if the dependencies have much overlap). There are a few different ways to set this up depending on exact requirements and preferences, there are a bunch explained here:
https://stackoverflow.com/a/2280289


The Microsoft DI framework has explicit support for scoped dependencies but idk if it's easy to use outside of asp.net

Adbot
ADBOT LOVES YOU

distortion park
Apr 25, 2011


In particular, your ViewModelFactory should either have the ViewModel's dependencies as its own dependencies, and then new one up as required (some say this is bad), or take in a function that creates ViewModel instances that is defined at app tree construction time (possibly using service location at that point)

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