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
NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Hammerite posted:

Visual Studio on my work machine is frequently getting itself into a state where it doesn't acknowledge certain keyboard inputs. It accepts printable characters, but it won't react to (for example) the enter key, the delete or backspace key, function keys, or combinations of meta and regular keys. The only way to fix it is to close and reopen VS. Anyone else had this?

:lol: I've had it too in the past, that bug will soon be old enough to drink and/or marry in some countries:

https://stackoverflow.com/questions/10786257/backspace-doesnt-work-in-visual-studio

Adbot
ADBOT LOVES YOU

epswing
Nov 4, 2003

Soiled Meat

NihilCredo posted:

:lol: I've had it too in the past, that bug will soon be old enough to drink and/or marry in some countries:

https://stackoverflow.com/questions/10786257/backspace-doesnt-work-in-visual-studio

On the one hand, experiencing this type of bug is certainly infuriating.

On the other, finding/fixing this type of bug probably also really, really sucks.

Just-In-Timeberlake
Aug 18, 2003

Hammerite posted:

Visual Studio on my work machine is frequently getting itself into a state where it doesn't acknowledge certain keyboard inputs. It accepts printable characters, but it won't react to (for example) the enter key, the delete or backspace key, function keys, or combinations of meta and regular keys. The only way to fix it is to close and reopen VS. Anyone else had this?

What version? Used to happen to me on 2019 but I can't recall it happening since I upgraded to 2022.

Hammerite
Mar 9, 2007

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

NihilCredo posted:

:lol: I've had it too in the past, that bug will soon be old enough to drink and/or marry in some countries:

https://stackoverflow.com/questions/10786257/backspace-doesnt-work-in-visual-studio

I didn't know that it could be fixed by opening and closing a menu. In my defense, why would that make a difference to anything? Visual Studio is simultaneously really clever and capable, and really stupid and clumsy.

Just-In-Timeberlake posted:

What version? Used to happen to me on 2019 but I can't recall it happening since I upgraded to 2022.

2022. I've had it installed for a couple of months but it's happened a lot in the last few days for no obvious reason

New Coke
Nov 28, 2009

WILL AMOUNT TO NOTHING IN LIFE.
I've found an odd bug in an old .Net Framework MVC app, and I'm not sure the best way to get it resolved.

Basically: there are a handful of routes that only allow POST requests. What's been happening, albeit somewhat infrequently, is that the user's session is expiring, they're clicking a button which sends a post request, and they're redirected to a login page (I'm aware that in-house authentication is a bad practice but that's kind of out of my hands), with the ReturnUrl query parameter set to the URL for that post request. On logging in, they're redirected to that endpoint, but because it's a redirect, they send a GET request, and end up with a 404.

I could always just write short GET versions of these routes which redirect to something sensible, but for the sake of maintainability, I was wondering if there's a way to deal with this such that I wouldn't have to add additional code for every POST-only endpoint? For example, is there a way to avoid populating the ReturnUrl parameter on a POST request?

B-Nasty
May 25, 2005

Another commonly used option for that issue is to track session timeout in JS (refreshed on every page load) and display a 'You are about to be logged out'-type message to the user. The JS can, when the timer expires, automatically call a logout method that clears any redirects.

(this is in addition to the session cookie timeout, and must be a smaller time window than that)

New Coke
Nov 28, 2009

WILL AMOUNT TO NOTHING IN LIFE.

B-Nasty posted:

Another commonly used option for that issue is to track session timeout in JS (refreshed on every page load) and display a 'You are about to be logged out'-type message to the user. The JS can, when the timer expires, automatically call a logout method that clears any redirects.

(this is in addition to the session cookie timeout, and must be a smaller time window than that)

Thanks, yeah that makes sense. Will probably go that route.

LongSack
Jan 17, 2003

CORS question.

I have an API running as an Azure app service. I also have a web front end in React, also running on an Azure web app.

When I first "installed" the two apps, everything worked fine. But suddenly I am getting CORS errors, and I have no clue as to why. I've tried using .AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod() to no avail. I originally used a named policy, but switched to a default policy. with no luck.

First appsettings.json:
code:
  "CORSOrigins": [
    "http://localhost:3000",
    "https://localhost:3000",
    "http://jimcoretailsite.azurewebsites.net",
    "https://jimcoretailsite.azurewebsites.net",
    "http://jimcoemployeeportal.azurewebsites.net",
    "https://jimcoemployeeportal.azurewebsites.net"
  ],
now the relevant sections of Program.cs:
C# code:
var origins = builder.Configuration.GetSection("CORSOrigins").Get<string[]>();
if (origins is null || !origins.Any())
{
  builder.Services.AddCors(options =>
  options.AddDefaultPolicy(builder =>
    builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
}
else
{
  builder.Services.AddCors(options =>
    options.AddDefaultPolicy(builder =>
    builder.WithOrigins(origins)
      .AllowAnyHeader()
      .AllowAnyMethod()));
}

...

app.UseCors();
and the error message:
Access to fetch at 'https://jimcoapi.azurewebsites.net/api/v1/Product/Random/3' from origin 'https://jimcoretailsite.azurewebsites.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled..

The site origin listed in the error message is one of the ones in the origins list.

I am sorely confused, especially since this all used to work.

Ideas?

coke zero mit mayo
Nov 5, 2008
Not sure why it would suddenly stop working but ave you checked the CORS settings in the app service itself? It's on the left side under API. The settings there seem to disallow everything by default.

Just-In-Timeberlake
Aug 18, 2003

LongSack posted:

CORS question.

I have an API running as an Azure app service. I also have a web front end in React, also running on an Azure web app.

When I first "installed" the two apps, everything worked fine. But suddenly I am getting CORS errors, and I have no clue as to why. I've tried using .AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod() to no avail. I originally used a named policy, but switched to a default policy. with no luck.

First appsettings.json:
code:
  "CORSOrigins": [
    "http://localhost:3000",
    "https://localhost:3000",
    "http://jimcoretailsite.azurewebsites.net",
    "https://jimcoretailsite.azurewebsites.net",
    "http://jimcoemployeeportal.azurewebsites.net",
    "https://jimcoemployeeportal.azurewebsites.net"
  ],
now the relevant sections of Program.cs:
C# code:
var origins = builder.Configuration.GetSection("CORSOrigins").Get<string[]>();
if (origins is null || !origins.Any())
{
  builder.Services.AddCors(options =>
  options.AddDefaultPolicy(builder =>
    builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
}
else
{
  builder.Services.AddCors(options =>
    options.AddDefaultPolicy(builder =>
    builder.WithOrigins(origins)
      .AllowAnyHeader()
      .AllowAnyMethod()));
}

...

app.UseCors();
and the error message:
Access to fetch at 'https://jimcoapi.azurewebsites.net/api/v1/Product/Random/3' from origin 'https://jimcoretailsite.azurewebsites.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled..

The site origin listed in the error message is one of the ones in the origins list.

I am sorely confused, especially since this all used to work.

Ideas?

Use your browser tools to start looking at the request/response header info, try multiple browsers since they might say slightly different things that might lead you to the solution. I've had this nonsense happen, and IE11 of all things gave me a message (that no other browser did) that was the clue I needed.

LongSack
Jan 17, 2003

Just-In-Timeberlake posted:

Use your browser tools to start looking at the request/response header info, try multiple browsers since they might say slightly different things that might lead you to the solution. I've had this nonsense happen, and IE11 of all things gave me a message (that no other browser did) that was the clue I needed.

Was going to remove my original post, but it actually wasn't a CORS error at all. There was a database mismatch that was causing an exception that was somehow showing up in the browser as a CORS error (which is truly baffling).

I had to delete the database and then restart the API which creates the database according to the most recent schema if it doesn't already exist.

No more CORS errors.

LongSack
Jan 17, 2003

coke zero mit mayo posted:

Not sure why it would suddenly stop working but ave you checked the CORS settings in the app service itself? It's on the left side under API. The settings there seem to disallow everything by default.

I've never enabled CORS at the app service level. I was curious about that too :shrug: but it seems unnecessary with ASP.Net Core's middleware.

necrotic
Aug 2, 2005
I owe my brother big time for this!

LongSack posted:

Was going to remove my original post, but it actually wasn't a CORS error at all. There was a database mismatch that was causing an exception that was somehow showing up in the browser as a CORS error (which is truly baffling).

I had to delete the database and then restart the API which creates the database according to the most recent schema if it doesn't already exist.

No more CORS errors.

CORS is a pre-flight check, the browser sends an OPTIONS request prior to the POST so the server can say yay or nay. The serving of that OPTIONS request throws a 500 it would fail CORS.

Whatever DB issue must have been occurring early enough in the chain to block the CORS handler.

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer
I have what feels like a simple problem:

In WPF: I have a DataGrid that is bound to an ObservableCollection<MyObject>, which can have up to hundreds of thousands of items in it. I frequently add to said ObservableCollection and the newest item is placed on the bottom of the DataGrid... But I want to place it on the top.

DataGrid receives an Index from the OC to determine where it should be placed. Placing it on the bottom is really easy - appending to an OC is an O(1) operation and that makes me real happy. However, appending to the beginning isn't really an option. What I'm trying to do here is avoid something that's O(n) every time I add an item.

The first option is pretty obvious: Don't use DataGrid. Build your own thing that reads from the back. The problem here is that that is still O(n) since you have to 'rebuild' from the back. To spare you some details, every thing I've thought of is *at least* linear time, and most of them are O(2n). My current implementation is to write to a 'holding OC', reverse it and use the reversed OC as my default search source, which means that the actual cost is O(3n) now. The nice thing is that this is very easy to write, but the perf has much to be desired.

Perhaps unsurprisingly, this is actually quite performant on my computer. At 10,000 items, the time to do that entire block of operations is <3ms, so that's definitely acceptable and I'm willing to just let it ride for now. At this point, I'm more academically curious about this problem then I am for practical reasons.

Is there a way to show the most recent item appended to an OC as the first item in a DataGrid (or any collection view) in less than O(n) time?

Canine Blues Arooo fucked around with this message at 18:53 on Jun 1, 2022

epswing
Nov 4, 2003

Soiled Meat

Canine Blues Arooo posted:

I have what feels like a simple problem:

In WPF: I have a DataGrid that is bound to an ObservableCollection<MyObject>, which can have up to hundreds of thousands of items in it. I frequently add to said ObservableCollection and the newest item is placed on the bottom of the DataGrid... But I want to place it on the top.

DataGrid receives an Index from the OC to determine where it should be placed. Placing it on the bottom is really easy - appending to an OC is an O(1) operation and that makes me real happy. However, appending to the beginning isn't really an option. What I'm trying to do here is avoid something that's O(n) every time I add an item.

The first option is pretty obvious: Don't use DataGrid. Build your own thing that reads from the back. The problem here is that that is still O(n) since you have to 'rebuild' from the back. To spare you some details, every thing I've thought of is *at least* linear time, and most of them are O(2n). My current implementation is to write to a 'holding OC', reverse it and use the reversed OC as my default search source, which means that the actual cost is O(3n) now. The nice thing is that this is very easy to write, but the perf has much to be desired.

Perhaps unsurprisingly, this is actually quite performant on my computer. At 10,000 items, the time to do that entire block of operations is <3ms, so that's definitely acceptable and I'm willing to just let it ride for now. At this point, I'm more academically curious about this problem then I am for practical reasons.

Is there a way to show the most recent item appended to an OC as the first item in a DataGrid (or any collection view) in less than O(n) time?

Not sure how to solve your specific problem offhand, but have you considered paging the collection? No human can 'browse' a list of 100,000+ records. Actually, you mentioned "search source", does that mean a user would search/filter the big list, and then edit the results?

Can you use sorting to solve your problem? I.e. who cares how your OC is ordered, just let the DataGrid sort it (maybe via CollectionViewSource)?

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

epswing posted:

Not sure how to solve your specific problem offhand, but have you considered paging the collection? No human can 'browse' a list of 100,000+ records. Actually, you mentioned "search source", does that mean a user would search/filter the big list, and then edit the results?

Can you use sorting to solve your problem? I.e. who cares how your OC is ordered, just let the DataGrid sort it (maybe via CollectionViewSource)?

This software is a 'remote logging' solution. Any apps can just bring a logging library and call Write with parameters and it'll blast a message to an arbitrary address, or just localhost. The use case is that you can have persistent logs regardless of app state, and your can consume logs from any number of apps simultaneously.

To that end, I'm not too interested in paging since that UX starts to suck under load. Yeah, a human doesn't really care about thousands of lines, but they generally care about the last dozen or so.

Talking this out presents a pretty obvious idea. Store the last few hundred in the 'active' OC, but just discard anything not recent and stash it in an 'everything' OC. If you want to search everything, expose that as an option. It'd keep things snappy.

raminasi
Jan 25, 2005

a last drink with no ice

Canine Blues Arooo posted:

I have what feels like a simple problem:

In WPF: I have a DataGrid that is bound to an ObservableCollection<MyObject>, which can have up to hundreds of thousands of items in it. I frequently add to said ObservableCollection and the newest item is placed on the bottom of the DataGrid... But I want to place it on the top.

DataGrid receives an Index from the OC to determine where it should be placed. Placing it on the bottom is really easy - appending to an OC is an O(1) operation and that makes me real happy. However, appending to the beginning isn't really an option. What I'm trying to do here is avoid something that's O(n) every time I add an item.

The first option is pretty obvious: Don't use DataGrid. Build your own thing that reads from the back. The problem here is that that is still O(n) since you have to 'rebuild' from the back. To spare you some details, every thing I've thought of is *at least* linear time, and most of them are O(2n). My current implementation is to write to a 'holding OC', reverse it and use the reversed OC as my default search source, which means that the actual cost is O(3n) now. The nice thing is that this is very easy to write, but the perf has much to be desired.

Perhaps unsurprisingly, this is actually quite performant on my computer. At 10,000 items, the time to do that entire block of operations is <3ms, so that's definitely acceptable and I'm willing to just let it ride for now. At this point, I'm more academically curious about this problem then I am for practical reasons.

Is there a way to show the most recent item appended to an OC as the first item in a DataGrid (or any collection view) in less than O(n) time?

Have you considered creating a custom backing structure that implements INotifyCollectionChanged?

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

raminasi posted:

Have you considered creating a custom backing structure that implements INotifyCollectionChanged?

I actually do, but it's based on OC. Since it needs to be thread safe, it's called ConcurrentObservableCollection.

Maybe going back to the drawing board on that might be the way.

zokie
Feb 13, 2006

Out of many, Sweden
Shouldn’t the list control be virtualized? Then if you are adding an item outside of the “viewing window” should that really cause new rendering?

And if you are displaying logs, why use a data grid? Those are for editing stuff, at least in my world

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

zokie posted:

Shouldn’t the list control be virtualized? Then if you are adding an item outside of the “viewing window” should that really cause new rendering?

And if you are displaying logs, why use a data grid? Those are for editing stuff, at least in my world

The DataGrid is temporary. It's a really easy to hand an object to something and say, 'draw data plz', but everything eventually will become a ListView.

It probably should be Virtualized.

power crystals
Jun 6, 2007

Who wants a belly rub??

Is there a compression library that has all of:
  • Reading basically whatever, but primarily zip/7z/rar
  • Writing zip and preferably 7z
  • Random-access reads
  • Updating existing archives by adding/renaming/deleting files to/from them
  • Extracting to and compressing from memory rather than disk (i.e. "take this byte[] and add it to Foo.zip as Bar")

There's a lot of 7-zip wrappers that of the ones I've tried either don't support memory read/write or are an extractor only, and they usually have an API made by an insane person. SharpCompress doesn't seem to support modifying existing archives. SharpZipLib hits most of what I want but doesn't support 7z even for reading. Does what I want actually exist?

LongSack
Jan 17, 2003

Using WPF in .Net Core 6. Does anyone know whether there is a difference in how commands are invoked on a button as opposed to in a KeyBinding?

When the button is clicked, or the keypad + key is hit, the method creates a viewmodel and shows a new window to get the new expense data. When the new window loads, the list of Payees and Expense Types is loaded from the database. This is done by using an attached dependency property which hooks into the WindowLoaded event.

If I click the button, the window loads and the WindowLoaded event runs, since the combo boxes are populated with the appropriate data.

If I hit the keypad + key, the window loads but the WindowLoaded method is never called - the combo boxes are empty.

It should be noted that the AddClick() method is an asynchronous method since it does database access.

I have this in my MainWindow:
code:
<Window.InputBindings>
    <KeyBinding Command="{Binding AddCommand}" Key="OemPlus" />
</Window.InputBindings>
		...
<Button Command="{Binding AddCommand}" ToolTip="Add a new Expense" ToolTipService.ShowOnDisabled="True">
    <Image Source="/resources/add-32.png" />
</Button>
this command:

C# code:
private AsyncCommand? _addCommand;
public ICommand AddCommand
{
    get
    {
        if (_addCommand is null)
        {
            _addCommand = new(AddClick, AddCanClick);
        }
        return _addCommand;
    }
}
and this:

C# code:
private bool AddCanClick() => PayeesExist && ExpenseTypesExist;

private async Task AddClick()
{
    var vm = _viewModelFactory.Create<ExpenseViewModel>();
    if (DialogSupport.ShowDialog<ExpenseWindow>(vm!, Application.Current.MainWindow) != true)
    {
        return;
    }
		...
}
the ExpenseWindow has an attached WindowLoaded method:

code:
<Window x:Class="XTrakr.Views.ExpenseWindow"
		...
        xmlns:vm="clr-namespace:XTrakr.ViewModels"
        xmlns:xi="clr-namespace:XTrakr.Infrastructure"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance Type=vm:ExpenseViewModel, IsDesignTimeCreatable=False}" Icon="/resources/moneybag-32.png" 
        xi:Behaviors.WindowLoadedBehavior="{Binding WindowLoadedCommand}" xi:DialogCloser.DialogResult="{Binding DialogResult}"
        Title="Add an Expense" Height="300" Width="500" WindowStartupLocation="CenterOwner" WindowStyle="ThreeDBorderWindow" SizeToContent="Height">
the WindowLoaded method itself:

C# code:
private async Task WindowLoaded()
{
    using var payeeService = _serviceFactory.Create<IPayeeService>();
    Payees = new((await payeeService!.GetAsync()).OrderBy(x => x.Name));
    using var expenseTypeService = _serviceFactory.Create<IExpenseTypeService>();
    ExpenseTypes = new((await expenseTypeService!.GetAsync()).OrderBy(x => x.Name));
}
and finally, the dependency property:

C# code:
// Window Loaded

public readonly static DependencyProperty WindowLoadedBehaviorProperty =
        DependencyProperty.RegisterAttached("WindowLoadedBehavior", typeof(ICommand),
        typeof(Behaviors), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None,
        OnWindowLoadedBehaviorChanged));
public static ICommand GetWindowLoadedBehavior(DependencyObject d) =>
    (ICommand)d.GetValue(WindowLoadedBehaviorProperty);
public static void SetWindowLoadedBehavior(DependencyObject d, ICommand value) =>
    d.SetValue(WindowLoadedBehaviorProperty, value);
public static void OnWindowLoadedBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is Window w)
    {
        w.Loaded += (s, a) =>
        {
            var command = GetWindowLoadedBehavior(w);
            if (command != null)
            {
                if (command.CanExecute(a))
                {
                    command.Execute(a);
                }
            }
        };
    }
}

epswing
Nov 4, 2003

Soiled Meat
I can't answer your actual question, but can you tell me why you want this code to run in a WindowLoaded method? Can't the VM be passed what it needs (an IEnumerable<Payee> and IEnumerable<ExpenseType>, or perhaps a IPayeeService and an IExpenseTypeService)? Basically it looks like the window is service-locating the services and then trying to pull out the objects, but this could be done earlier, and perhaps automatically by your DI container, upon creation of the ExpenseViewModel.

LongSack
Jan 17, 2003

epswing posted:

I can't answer your actual question, but can you tell me why you want this code to run in a WindowLoaded method? Can't the VM be passed what it needs (an IEnumerable<Payee> and IEnumerable<ExpenseType>, or perhaps a IPayeeService and an IExpenseTypeService)? Basically it looks like the window is service-locating the services and then trying to pull out the objects, but this could be done earlier, and perhaps automatically by your DI container, upon creation of the ExpenseViewModel.

The reason I'm using factories for dependencies rather than constructor injection is this:

MainViewModel is responsible for invoking all of the other windows with their respective view models. Using constructor injection, I would inject those other view models into the MainViewModel. Then those view models have dependencies on the data services, so again using constructor injection those services would be passed. Then those data services are dependent on the data repositories.

So, when the MainViewModel gets instantiated, all of it's constructor dependencies get instantiated, and all of their dependencies get instantiated ... all the way down.

Thus, instantiating the MainViewModel basically instantiates the entire application.

So I'm trying to avoid that by using factories to instantiate them as needed.

If you know of a way that I can use constructor injection without cascading the entire application, I'd love to hear it, because all I can come up with is using factories. And I'm not being sarcastic or snarky at all, I seriously mean that.

Admittedly, I could instantiate them using factories in the MainViewModel and then pass them down to the other view models as needed, but that just moves things around and is a distinction without a real difference, IMO. The Factories do pull from the DI container, so things are still loosely coupled:

C# code:
public interface IViewModelFactory
{
    T? Create<T>() where T : ViewModelBase;
}

public class ViewModelFactory : IViewModelFactory
{
    private readonly IServiceProvider? _serviceProvider;

    public ViewModelFactory()
    {
        var app = Application.Current as App;
        _serviceProvider = app?.ServiceProvider;
    }

    public T? Create<T>() where T : ViewModelBase => _serviceProvider?.GetRequiredService<T>();
}

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

LongSack posted:

The reason I'm using factories for dependencies rather than constructor injection is this:

MainViewModel is responsible for invoking all of the other windows with their respective view models. Using constructor injection, I would inject those other view models into the MainViewModel. Then those view models have dependencies on the data services, so again using constructor injection those services would be passed. Then those data services are dependent on the data repositories.

So, when the MainViewModel gets instantiated, all of it's constructor dependencies get instantiated, and all of their dependencies get instantiated ... all the way down.

Thus, instantiating the MainViewModel basically instantiates the entire application.

So I'm trying to avoid that by using factories to instantiate them as needed.

If you know of a way that I can use constructor injection without cascading the entire application, I'd love to hear it, because all I can come up with is using factories. And I'm not being sarcastic or snarky at all, I seriously mean that.

Admittedly, I could instantiate them using factories in the MainViewModel and then pass them down to the other view models as needed, but that just moves things around and is a distinction without a real difference, IMO. The Factories do pull from the DI container, so things are still loosely coupled:

C# code:
public interface IViewModelFactory
{
    T? Create<T>() where T : ViewModelBase;
}

public class ViewModelFactory : IViewModelFactory
{
    private readonly IServiceProvider? _serviceProvider;

    public ViewModelFactory()
    {
        var app = Application.Current as App;
        _serviceProvider = app?.ServiceProvider;
    }

    public T? Create<T>() where T : ViewModelBase => _serviceProvider?.GetRequiredService<T>();
}

This is literally service locator pattern, and it sucks for reasons found on many blog posts.

If your concern is performance (e.g. something about the construction has a slow load time), instantiate the dependencies using Lazy<> so the initialization doesn't happen until the service is actually used.

Kyte
Nov 19, 2013

Never quacked for this
At least centralize your service location and member initialization into the viewmodel factory (if necessary add and call an InitAsync after creation and before returning).
IMO the combobox should have a simple binding to ObservableCollections in the viewmodel and nothing more.

wrt the original issue: Does the Loaded event not fire at all or is the problem somewhere down the chain? Is your loaded event actually being attached by OnWindowLoadedBehaviorChanged?

LongSack
Jan 17, 2003

Bruegels Fuckbooks posted:

This is literally service locator pattern, and it sucks for reasons found on many blog posts.

If your concern is performance (e.g. something about the construction has a slow load time), instantiate the dependencies using Lazy<> so the initialization doesn't happen until the service is actually used.

I originally went with this method (in WPF only) because I was using EF Core and in that case the Repositories all had a dependency on the DbContext, which was designed to be created and destroyed as needed, not to sit around.

Now that I’m using Dapper over ADO.Net, it is probably not an issue. I could use the factories in the MainViewModel and have all the other dependencies handled via constructor injection at the “second level” and below.

Or maybe just say gently caress it and let the whole thing instantiate so it’s turtles all the way down.

I’ll give it a try. This is a fairly small app, just a simple expense tracker, so it might not even matter.

I’ll also look into that Lazy thing, I’m not familiar. Thanks

EDIT: I changed the view models to use constructor-based injection. The app uses about 18MB more memory when running, but everything still works fine now that I'm not using EF Core for database access.

LongSack fucked around with this message at 14:40 on Jun 17, 2022

LongSack
Jan 17, 2003

Kyte posted:

wrt the original issue: Does the Loaded event not fire at all or is the problem somewhere down the chain? Is your loaded event actually being attached by OnWindowLoadedBehaviorChanged?

All I can say is that if I set a breakpoint in the WindowLoaded method, if I click the add button, the breakpoint gets hit. If I use the plus key, it does not. The code paths should be identical unless there’s something I don’t know about KeyBindings.

I’ve done this before in many apps without an issue. The only difference between this app and those is that for async command methods I’m using an AsyncCommand versus a RelayCommand.

EDIT: Setting various breakpoints, I can tell that the Loaded event IS getting hooked, but the method is NOT getting called when I use the KeyBinding, but IS getting called when I press the button.

Second edit: It’s all moot now anyway, I just have the MainViewModel set the properties for Payees and ExpenseTypes in the ExpenseViewModel before the window is shown. Still extremely curious as to what is going on, but I gotta get on with my life …

LongSack fucked around with this message at 23:04 on Jun 17, 2022

epswing
Nov 4, 2003

Soiled Meat
Question for you warriors that have migrated projects from .NET 4.8 to .NET 6.

I've got an ASP.NET project now targeting framework ".NET 6" and target OS "Windows" (i.e. the line in the csproj file is <TargetFramework>net6.0-windows</TargetFramework>, and did the work to also switch to EF Core. Builds find locally. When I try to publish to Azure via DevOps pipeline, it fails during the NuGet Restore step, with the error:

quote:

NU1202:
Package Microsoft.EntityFrameworkCore 6.0.5 is not compatible with net60-windows (.NETFramework,Version=v6.0,Profile=windows).
Package Microsoft.EntityFrameworkCore 6.0.5 supports: net60 (.NETFramework,Version=v6.0)

I'm confused about what this is telling me. NuGet is pulling in an in compatible version of EF Core? Or a version of EF Core that targets .NET 6 but not Windows?

ThePeavstenator
Dec 18, 2012

:burger::burger::burger::burger::burger:

Establish the Buns

:burger::burger::burger::burger::burger:

epswing posted:

Question for you warriors that have migrated projects from .NET 4.8 to .NET 6.

I've got an ASP.NET project now targeting framework ".NET 6" and target OS "Windows" (i.e. the line in the csproj file is <TargetFramework>net6.0-windows</TargetFramework>, and did the work to also switch to EF Core. Builds find locally. When I try to publish to Azure via DevOps pipeline, it fails during the NuGet Restore step, with the error:

I'm confused about what this is telling me. NuGet is pulling in an in compatible version of EF Core? Or a version of EF Core that targets .NET 6 but not Windows?

That's weird. the TFM "net6.0" basically means "any platform that can run .NET 6 can take a dependency on this", where "net6.0-windows" means ".NET 6.0 minimum, with Windows-specific APIs" - https://docs.microsoft.com/en-us/dotnet/standard/frameworks#net-5-os-specific-tfms

What happens if you just use "net6.0" instead of "net6.0-windows"?

epswing
Nov 4, 2003

Soiled Meat

ThePeavstenator posted:

That's weird. the TFM "net6.0" basically means "any platform that can run .NET 6 can take a dependency on this", where "net6.0-windows" means ".NET 6.0 minimum, with Windows-specific APIs" - https://docs.microsoft.com/en-us/dotnet/standard/frameworks#net-5-os-specific-tfms

What happens if you just use "net6.0" instead of "net6.0-windows"?

My app has to target net6.0-windows for some windowsy reasons I can't remember now.

However, I found my problem, the pipeline was pulling in NuGet v4.4.1, and after checking in VS 2022 -> Help -> About I see that I'm building my solution with NuGet v6.2.1. I changed the NuGet tool installer task in the DevOps pipeline to 6.2.1 and the restore task worked!

Now I have a new problem that I can't seem to google correctly. The pipeline publishes/deploys to Azure app service. Under Configuration -> General Settings -> .NET version I've switched from "ASP.NET V4.8" to ".NET 6 (LTS)", however when I visit the site I'm getting:

quote:

HTTP Error 500.31 - ANCM Failed to Find Native Dependencies
The specified version of Microsoft.NetCore.App or Microsoft.AspNetCore.App was not found

If it were IIS this would mean I forgot to install the hosting bundle. In Azure, I've restarted the app service, seems to be configured correctly by all accounts. I opened cloud shell and ran az webapp config show --resource-group foo --name bar and in the response I can see

code:
{
  ...
  "name": "bar",
  "netFrameworkVersion": "v6.0",
  ...
  "resourceGroup": "foo",
}
Nothing shows in the streaming logs.

How do I convince Azure that the app service and my project are both targeting .NET 6 and should be happy?

ThePeavstenator
Dec 18, 2012

:burger::burger::burger::burger::burger:

Establish the Buns

:burger::burger::burger::burger::burger:
Are you invoking MSBuild in your ADO pipeline or are you using dotnet build? NuGet/MSBuild are integrated in dotnet, so you shouldn't need to deal with NuGet versions like that as a separate tool.

epswing
Nov 4, 2003

Soiled Meat

ThePeavstenator posted:

Are you invoking MSBuild in your ADO pipeline or are you using dotnet build? NuGet/MSBuild are integrated in dotnet, so you shouldn't need to deal with NuGet versions like that as a separate tool.

Y’know, it’s sounding more and more like instead of editing my existing pipeline I need to throw it out and start from scratch. Thanks for pointing me in the right direction.

raminasi
Jan 25, 2005

a last drink with no ice
Here's a weird new thing I'm running into: I've got a WPF tab control with headers defined like so:

code:
<TabItem.Header>
  <TextBlock Text="Title Text" Margin="2,0,0,0" />
</TabItem.Header>
(That's a weird way to define a tab item header, but it's the minimal reproduction case.) When the application runs, the headers don't render unless I comment out the header code, save the .xaml file, comment it back in, save the file again, and hot reload :psyduck: No debugger attached? Hope you didn't want to see those headers!

raminasi fucked around with this message at 17:24 on Jul 4, 2022

epswing
Nov 4, 2003

Soiled Meat
Is MAUI still a nightmare or if one wanted to build a dead simple LOB (i.e. load list of records from API, open record, edit simple fields, save record) it’s kinda alright?

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

epswing posted:

Is MAUI still a nightmare or if one wanted to build a dead simple LOB (i.e. load list of records from API, open record, edit simple fields, save record) it’s kinda alright?

I'm not a MAUI expert. I'm a huge WPF simp. With that said...

If you know WPF and are targeting the the Windows desktop, there is absolutely no reason to not use WPF. If you must be xplatform, then you could do a lot worse.

epswing
Nov 4, 2003

Soiled Meat

Canine Blues Arooo posted:

I'm not a MAUI expert. I'm a huge WPF simp. With that said...

If you know WPF and are targeting the the Windows desktop, there is absolutely no reason to not use WPF. If you must be xplatform, then you could do a lot worse.

Sorry, I should have mentioned, we have several native Windows desktop apps written in WPF, and I'm considering MAUI for iOS/Android mobile development.

Drastic Actions
Apr 7, 2009

FUCK YOU!
GET PUMPED!
Nap Ghost
The most stable part of MAUI right now is MAUI Blazor. If you want to ship something right now, I would use that. Otherwise, I would follow the traditional Xamarin playbook of building out your UI Logic as a .NET Standard library that's platform independent, and then create native platform heads each one to want to target and avoid MAUIs baked in controls. If and when MAUI becomes more stable, you can use "native embedded" to inject MAUI controls into your native app and you'll have the best of both worlds.

I've been working on some samples showing off that idea: https://github.com/drasticactions/dotnetrss.

mortarr
Apr 28, 2005

frozen meat at high speed
Is it still the consensus that wrapping widely-used or cross-cutting functionality like logging is the way to go, or is there some other pattern I've missed?

In the past I used to use log4net, but I would typically have an interface in a common project that wrapped and hid everything, then wire it up at app-startup with whatever DI/IoC dealio I was using in the executable project, and then the rest of my projects or unit tests would be completely indifferent to the fact it was log4net doing the heavy lifting and would only need to reference code in the common project.

Swapping over to Serilog, and trying to save myself some headaches, but not sure if the headache is more in writing the code to wrap the serilog ILogger interface with my own, or in hiding that it's Serilog that I'm using (eg. should I just take a reference to the Serilog ILogger interface everywhere).

Not sure I've written my thoughts down very clearly, and hoping for a pattern rather than something about using serilog itself, so hope this makes sense

mortarr fucked around with this message at 05:27 on Jul 8, 2022

Adbot
ADBOT LOVES YOU

redleader
Aug 18, 2005

Engage according to operational parameters

mortarr posted:

Is it still the consensus that wrapping widely-used or cross-cutting functionality like logging is the way to go, or is there some other pattern I've missed?

i'm not qualified to comment on the general case. however, specifically for logging, you should use the first-party ILogger<T> logging API from Microsoft.Extensions.Logging. nowadays, drat near every logging library provides an easy way to register its loggers with the MS logging framework, and your libraries/frameworks should use it for their internal logging - giving you one place to configure logging for everything. relevant to you: serilog has the Serilog.Extensions.Logging package that provides easy integration into Microsoft.Extensions.Logging.

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