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
Sab669
Sep 24, 2009

Bognar posted:

Yeah that should work - return type doesn't have any effect on the parameter binding.

Well, with your route I no longer get the deserializer error, but the value passed to my controller is null.

In the JavaScript I can see the value contains what I expect, but get nothing on the other side.


I've tried adding processData: false as well as mimeType: "multipart/form-data" to the actual ajax message, and creating a FormData object in the JS to pass instead of just the stringified object like i was before: data = new FormData("myData", JSON.stringify(data));

No dice :(

Adbot
ADBOT LOVES YOU

Essential
Aug 14, 2003
Is there a way when querying a database with Entity Framework to exclude duplicates? I will need to check on 4 or 5 fields, if they are all the same, it's a duplicate and I'd like to only grab 1 record, ignoring all the duplicates.

If I can't do it in the query then I assume I'll have to enumerate the list and create a new list excluding duplicates.

Essential
Aug 14, 2003

Sab669 posted:

Well, with your route I no longer get the deserializer error, but the value passed to my controller is null.

In the JavaScript I can see the value contains what I expect, but get nothing on the other side.


I've tried adding processData: false as well as mimeType: "multipart/form-data" to the actual ajax message, and creating a FormData object in the JS to pass instead of just the stringified object like i was before: data = new FormData("myData", JSON.stringify(data));

No dice :(

Not sure will help, but for an azure wcf service we have to set these in the web.config in order to pass large strings:
code:
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding maxReceivedMessageSize="10485760">
          <readerQuotas maxStringContentLength="10485760" />
        </binding>
      </basicHttpBinding>
    </bindings>

EssOEss
Oct 23, 2006
128-bit approved
Are there fields being selected that do not determine uniqueness? If all fields matter for uniqueness checks, just slap a .Distinct() on the end. Not sure how to do it if only a subset of the fields determines uniqueness, though.

Essential
Aug 14, 2003

EssOEss posted:

Are there fields being selected that do not determine uniqueness? If all fields matter for uniqueness checks, just slap a .Distinct() on the end. Not sure how to do it if only a subset of the fields determines uniqueness, though.

That's a good question. At least for the majority of the queries I should be able to only select unique fields. Thanks for the .Distinct() suggestion, I'll run with that until I have a situations where I need to get non-unique fields.

That's assuming I can use .Distinct() when selecting into a new group, the group containing just the unique fields. Something like this I think:

Edit: group by not needed.

code:
var q = from context.BrokenAppointments
select new DTO {
	Field1 = r.Field1,
	Field2 = r.Field2,
	etc.
}.Distinct().ToList();

Essential fucked around with this message at 00:30 on Oct 14, 2016

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Sab669 posted:

Well, with your route I no longer get the deserializer error, but the value passed to my controller is null.

In the JavaScript I can see the value contains what I expect, but get nothing on the other side.


I've tried adding processData: false as well as mimeType: "multipart/form-data" to the actual ajax message, and creating a FormData object in the JS to pass instead of just the stringified object like i was before: data = new FormData("myData", JSON.stringify(data));

No dice :(

Check the request in the network tab of your browser dev tools (hit F12) to see exactly what is being sent in the form data. Also, in your MVC action, you can debug and read through the values of Request.Form to see what MVC thinks your form looks like.

I may have gotten the syntax wrong for sending form data via jQuery.

Bognar fucked around with this message at 21:17 on Oct 13, 2016

Gul Banana
Nov 28, 2003

spent another few hours today fixing ReflectPropertyDescriptor memory leaks :-(

Gul Banana
Nov 28, 2003

lol, it's been codified as a Known Problem to presumably never fix?? https://support.microsoft.com/en-us/kb/938416

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Ciaphas posted:

Thanks, I'll have to read up on EF, I haven't any real clue how it differs (or how data interactions in C#/.net work at all yet, really)

LINQ to SQL basically a significantly more limited version of EF. LINQ to SQL has also been considered completely dead for years now.

raminasi
Jan 25, 2005

a last drink with no ice
I'm not sure whether this is more properly an HTTP question or a .NET question, but I'm having trouble getting an HttpClient to send back cookies it received as part of a response. My understanding was that if I gave my HttpClient an HttpClientHandler with UseCookies set to true, then cookies received in responses would be sent back with subsequent requests, as long as the URIs matched. I know the cookies are being returned on the first call:
code:
let handler = new HttpClientHandler(UseCookies=true)
let httpClient = new HttpClient(handler, disposeHandler=true)
// blah blah
let! response = httpClient.PostAsync(endpoint, content) |> Async.AwaitTask
// cookies are set at this point
But then later:
code:
// They're not sent here!
let! response2 = httpClient.PostAsync(endpoint2, content2) |> Async.AwaitTask
I verified that handler.CookieContainer.GetCookieHeader(endpoint2) produces the cookie header I expect - it's just not in the request that's generated for the second PostAsync call (I checked it by inserting a logging DelegatingHandler). Am I just misunderstanding what HttpClient is for, or am I forgetting some stupid thing?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


New Yorp New Yorp posted:

LINQ to SQL basically a significantly more limited version of EF. LINQ to SQL has also been considered completely dead for years now.

Really? Man keeping up with events is hard without reliable 'net access at your regular work computer, I tell you what. All I've got is five or six year old C#/.NET books for reference.

EssOEss
Oct 23, 2006
128-bit approved
What's the latest state of non-nullable reference types in C#? Has there been a proposal for implementing this concept that stands out from the others? I know it's a rather tricky topic and there were several different approaches proposed some time ago.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
https://github.com/dotnet/roslyn/issues/5032

Current approach is to consider all types to be non-nullable, and use ? to denote nullable types. The compiler can then warn or error when trying to pass a known nullable type as a non-nullable type. For backwards compatibility reasons, however, there is no separate non-nullable type. When a type is used in a non-nullable fashion it is just given an attribute to indicate that. This allows older compilers to consume the new code without issue, but also allow newer compilers to warn about nullability.

As I understand, it's not expected for this to be released in C# 7.

Sab669
Sep 24, 2009

Just following up with my issues last week; I was able to figure it out and send the data using FormData; just needed change up how I was trying to access it on the server side. Thanks for the help Bognar!

Night Shade
Jan 13, 2013

Old School

Bognar posted:

As I understand, it's not expected for this to be released in C# 7.

I'm not surprised by this, it's a pretty huge change, but good god it can't come soon enough.

chippy
Aug 16, 2006

OK I DON'T GET IT
If I've got an async method that might throw an exception I want to handle, is it just the part where I'm awaiting it that I need to wrap in a try/catch? Or do I also need to wrap the initial call to the method where I get a reference to the Task it returns?

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
Just wrap the await with try{}.

EssOEss
Oct 23, 2006
128-bit approved
I would says you need to care for both. An async method may execute code synchronously, after all!

code:
async Task Whatever()
{
    throw new Exception("This gets thrown when you call it, not when you await the result.");
    
    await Task.Delay(1234);

    throw new Exception("This would get thrown when you await the task, if it were not unreachable code. Unless Task.Delay also completes synchronously, which it probably won't.");
}
Unless I misunderstand how it works?

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
e: nm

Bognar fucked around with this message at 14:59 on Oct 20, 2016

ljw1004
Jan 18, 2005

rum

EssOEss posted:

I would says you need to care for both. An async method may execute code synchronously, after all!

code:

async Task Whatever()
{
    throw new Exception("This gets thrown when you call it, not when you await the result.");
    
    await Task.Delay(1234);

    throw new Exception("This would get thrown when you await the task, if it were not unreachable code. Unless Task.Delay also completes synchronously, which it probably won't.");
}

Unless I misunderstand how it works?

You've misunderstood... The above code will NEVER throw merely upon invoking "var t = Whatever()". It will only throw when you "await t". That's because, in a method with the async modifier, every single exception gets stored in the returned task object.


Here instead is an implementation of Whatever that might throw in both places. It achieves this by a wrapper method that lacks the async modifier.

code:

Task Whatever(string s) {
   if (s == null) throw new ArgumentNullException(named(s));
   return WhateverInner(s);
}

async Task WhateverInner(string s) {
   if (s.length < 1) throw new xyz;
   await Task.Delay(10);
   Throw new abc;
}

Some folks believe this is good practice. They are wrong. If you find anyone, report them, and they can be sent to the salt puts for education.

And I wouldn't even bother coding defensively to defend against this perverse pattern.

redleader
Aug 18, 2005

Engage according to operational parameters

ljw1004 posted:

Here instead is an implementation of Whatever that might throw in both places. It achieves this by a wrapper method that lacks the async modifier.

code:

Task Whatever(string s) {
   if (s == null) throw new ArgumentNullException(named(s));
   return WhateverInner(s);
}

async Task WhateverInner(string s) {
   if (s.length < 1) throw new xyz;
   await Task.Delay(10);
   Throw new abc;
}

Some folks believe this is good practice. They are wrong. If you find anyone, report them, and they can be sent to the salt puts for education.

Stupid newbie question, but why is this considered bad practice? It looks very similar to the sort of thing you'd do when writing an iterator method:

C# code:

public static IEnumerable<string> Repeat(string s) {
    if (s == null) { throw new ArgumentNullException();}
    return RepeatInner(s);
}

private static IEnumerable<string> RepeatInner(string s) {
    while (true) { yield return s; }
}

I've never really had much chance to play around with async/await.

EssOEss
Oct 23, 2006
128-bit approved

ljw1004 posted:

You've misunderstood...

Thanks for setting me straight! I can sleep more soundly now.

quote:

Stupid newbie question, but why is this considered bad practice? It looks very similar to the sort of thing you'd do when writing an iterator method

I believe he specifically means for the reason that this would make the exception throw before the Task is awaited. The pattern itself, without having the inner private method be async, is fine and indeed often used (filter crap out at public API and assume inner API is properly used).

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

ljw1004 posted:

You've misunderstood... The above code will NEVER throw merely upon invoking "var t = Whatever()". It will only throw when you "await t". That's because, in a method with the async modifier, every single exception gets stored in the returned task object.

Well I learned something today. Is there a specific reason for this behavior, that all exceptions are stored on the task rather than just the ones run asynchronously? This is even more divergence from the simple but conceptually helpful model of thinking of async/await as promise chaining.

Sedro
Dec 31, 2008

redleader posted:

Stupid newbie question, but why is this considered bad practice? It looks very similar to the sort of thing you'd do when writing an iterator method:
[/code]

I've never really had much chance to play around with async/await.

It forces the caller to handle exceptions twice: once when constructing the Task and again through the Task interface.

If a method returns a Task, any exception should go through the return value; it should never throw an exception. The same goes for other abstractions like Rx Observables.

ljw1004
Jan 18, 2005

rum

Bognar posted:

Well I learned something today. Is there a specific reason for this behavior, that all exceptions are stored on the task rather than just the ones run asynchronously? This is even more divergence from the simple but conceptually helpful model of thinking of async/await as promise chaining.

The question of "which ones are run asynchronously" is pretty unpredictable...

DEFINE: we'll say an exception is thrown synchronously if it comes from merely invoking var t = FredAsync(i). We'll say it's thrown asynchronously if it's thrown when you await t.

code:
async Task FredAsync(int s)
{
   throw new Exception("A");   // this one is definitely synchronous
   await Task.Delay(s);
   throw new Exception("B");  // will be synchronous if s == 0
   var b = await buffer.GetNextByte();
   throw new Exception("D");  // will be synchronous if next byte were cached
   await Task.Delay(1);
   throw new Exception("E");  // this is the only one assuredly not synchronous
}
It'd be hard to code reliably around this kind of behavior. Typical "hidden bug" scenario would be one in which you tested your code to work correctly when consumed like this
code:
  var t = FredAsync();
  try { await t; }
  catch (Exception ex) { }
But then at runtime in a small number of cases it ends up throwing synchronously that you hadn't tested.

A bad situation would be if people always stuck await Task.Yield() inside their async methods to guarantee that the exception would be stored inside the Task. This would indeed make their code reliable, but it'd come at the cost of efficiency.



"But ljw1004, what if C# made it so all exceptions before the first COLD await get thrown synchronously, and exceptions after the first await get stored in the Task?"

(A hot await is one that returns immediately without needing to do the costly async machinery, e.g. await Task.Delay(0) or await buffer.GetNextByteAsync() in the case where the next byte is already in the buffer. A cold await is one that does involve the async machinery, does involve allocating the async state machine on the heap, does involve allocating a Task object on the heap.)

Consider this code:

code:
async Task JonesAsync(bool b)
{
   if (b) await Task.Delay(10);
   throw new Exception("F");
}
In this case the exception would sometimes be thrown synchronously and sometimes not. Again you'd be led into the pit of failure of not testing every possibility.


By making all exceptions get stored in the Task, it reduces the complexity and the number of code-paths you have to think about.

ljw1004 fucked around with this message at 17:28 on Oct 20, 2016

ljw1004
Jan 18, 2005

rum

redleader posted:

Stupid newbie question, but why is this considered bad practice? It looks very similar to the sort of thing you'd do when writing an iterator method:

It's cumbersome to produce (i.e. expecting everyone to implement "inner and outer" methods).

It's cumbersome to consume (i.e. expecting everyone to write try/catch blocks twice).

I think it just wouldn't add enough efficiency or reliability to software to justify those two cumbersomes.



The analogy to iterator methods is an interesting one. I think one difference might be that when you return an IEnumerable then it might potentially be consumed many times (and so repeating the parameter validation each time feels weird). Although this reason doesn't extend to IEnumerator-returning iterator methods.


There's an interesting connection with asynchronous streams, IAsyncEnumerable (which is part of RX). Consider how Entity Framework exposes itself as an IAsyncEnumerable...
code:
interface IAsyncEnumerable<T>
{
   IAsyncEnumerator<T> GetAsyncEnumerator();
}

interface IAsyncEnumerator<T>
{
   async Task<bool> MoveNextAsync();
   T Current {get;}
}
EF has to initialize its async streams asynchronously: it has to negotiate a connection with the database, so validating the connection parameters, even before it can start iterating through the rows. You'd think therefore that the signature should be
code:
  Task<IAsyncEnumerator<T>> GetAsyncEnumeratorAsync();
But it's not. Instead EF defers that work until the first time you await en.MoveNextAsync().

I don't have any profound lessons to draw from this connection! Merely that the question of whether work (and validation and exceptions) happen eagerly or later on is a complicated one. I hope it always steers in the direction of making reliable the sort of code that people will realistically write.

NihilCredo
Jun 6, 2011

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

God drat it, is there a sensible best practice for figuring out whether a given SqlException is caused by a connection/login problem or by an error in the query/schema?

Googling only suggests an old third-party transient fault handling framework that isn't online anymore, and in any case appears to have relied on a huge list of individual SqlError numbers that wasn't even complete. (Our current error handling is also a list of error numbers, but isn't even huge).

EssOEss
Oct 23, 2006
128-bit approved
That good old "list of error codes" is how I have always seen it done. Though usually it has been a rather short list, more of a "catch the top 10 common things" sort of thing.

NihilCredo
Jun 6, 2011

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

EssOEss posted:

That good old "list of error codes" is how I have always seen it done. Though usually it has been a rather short list, more of a "catch the top 10 common things" sort of thing.

That's basically what we had, but we've been having more and more failures due to unrecognised error codes (might or might not be related to the upgrade to newer editions of Windows and MSSQL).

Our software handles server and network failures by switching to a local fallback server which enables basic functionality only, so unfortunately both false positives and false negatives are going to cause problems.

It's baffling that the .NET exception system encourages the use of inheritance so much, yet in this case (which would be, IMO, a perfect fit) we're stuck looking up a webpage with 30k+ integers, instead of having a neat categorisation through subclasses.

Gul Banana
Nov 28, 2003

i've complained about nuget 3 performance in the past, so i just wanted to check in to mention that it's not bad at all anymore. as long as you use project.json/transitive restore, it's now faster than 2 was

Dr Monkeysee
Oct 11, 2002

just a fox like a hundred thousand others
Nap Ghost

ljw1004 posted:

The question of "which ones are run asynchronously" is pretty unpredictable...

Seems like there's a much simpler answer to this question which is: as the caller you'd have to know which statements throw before the first await in the method body and which statements throw after the first await in the method body.

Which is... madness. That would be completely unworkable the second you hit an async method that isn't your own code.

CapnAndy
Feb 27, 2004

Some teeth long for ripping, gleaming wet from black dog gums. So you keep your eyes closed at the end. You don't want to see such a mouth up close. before the bite, before its oblivion in the goring of your soft parts, the speckled lips will curl back in a whinny of excitement. You just know it.
I'm working on a WPF project and I'm just stacking up templates that are drat near identical to each other except for one thing. Look at this:
code:
<ControlTemplate x:Key="btn_menu" TargetType="{x:Type Button}">
	<Grid x:Name="grd" Background="#000000" Height="100">
		<TextBlock x:Name="txt_content" Text="{TemplateBinding Content}" 
		Style="{StaticResource txt_menu}" HorizontalAlignment="Center"
 		VerticalAlignment="Center"/>
	</Grid>
	<ControlTemplate.Triggers>
		<Trigger Property="Button.IsPressed" Value="True">
			<Setter TargetName="grd" Property="Background" Value="#E5212D" />
		</Trigger>
	</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="btn_menu_red" TargetType="{x:Type Button}">
	<Grid x:Name="grd" Background="#E5212D" Height="100">
		<TextBlock x:Name="txt_content" Text="{TemplateBinding Content}" 
		Style="{StaticResource txt_menu}" HorizontalAlignment="Center" 
		VerticalAlignment="Center"/>
	</Grid>
	<ControlTemplate.Triggers>
		<Trigger Property="Button.IsPressed" Value="True">
			<Setter TargetName="grd" Property="Background" Value="#000000" />
		</Trigger>
	</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="btn_menu_border" TargetType="{x:Type Button}">
	<Grid x:Name="grd" Background="#000000" Height="100">
		<TextBlock x:Name="txt_content" Text="{TemplateBinding Content}" 
		Style="{StaticResource txt_menu}" HorizontalAlignment="Center" 
		VerticalAlignment="Center"/>
		<Canvas Width="1" Height="60" Background="#4A4040" HorizontalAlignment="Left"
 		VerticalAlignment="Center"/>
	</Grid>
	<ControlTemplate.Triggers>
		<Trigger Property="Button.IsPressed" Value="True">
			<Setter TargetName="grd" Property="Background" Value="#E5212D" />
		</Trigger>
	</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="btn_menu_selected" TargetType="{x:Type Button}">
	<Grid x:Name="grd" Background="#000000" Height="100">
		<TextBlock x:Name="txt_content" Text="{TemplateBinding Content}" 
		Style="{StaticResource txt_menu_red}" HorizontalAlignment="Center" 
		VerticalAlignment="Center"/>
	</Grid>
</ControlTemplate>
I'm driving myself crazy. Is there some cute trick I don't know where I can make, like, whatever the WPF template version of an interface is, and then just make a bunch of templates that just pass in variables for text style, background color, and is there a border yes/no? (And yes, I'm using all of these multiple times, so there's a reason to actually make templates in the first place.)

CapnAndy fucked around with this message at 18:53 on Oct 21, 2016

iron buns
Jan 12, 2016

CapnAndy posted:

I'm working on a WPF project and I'm just stacking up templates that are drat near identical to each other except for one thing. Look at this:

I'm driving myself crazy. Is there some cute trick I don't know where I can make, like, whatever the WPF template version of an interface is, and then just make a bunch of templates that just pass in variables for text style, background color, and is there a border yes/no? (And yes, I'm using all of these multiple times, so there's a reason to actually make templates in the first place.)

You could pass the values as attached properties and create a bunch of styles to set those properties along with the control template.

iron buns fucked around with this message at 22:58 on Oct 21, 2016

Gul Banana
Nov 28, 2003

what you want there is a custom control, with a default style referenced from Themes/Generic.xaml and some TemplateBindings

SmellsLikeToast
Dec 30, 2005

A GREATER MAN THAN I DESERVE
I'm looking for the absolute most zen simple way to add a sound effect to a UWP project. What I have now is extremely clunky and seems way too complicated to be effective with multiple sounds. For reference:
code:
{

    public class mySoundEffectClass
    {
        public MediaElement mySound { get; }

        public mySoundEffectClass()
        {
            this.mySound = new MediaElement();
            this.buildSound();
        }

        private async void buildSound()
        {
            Windows.Storage.StorageFolder folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
            Windows.Storage.StorageFile file = await folder.GetFileAsync("sound.wav");
            var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
            this.mySound.SetSource(stream, file.ContentType);


        }

    }
}
It's simple enough to access from another class by just calling mySound.Play(), but that is a shitload of code to repeat for each sound. I know there has to be a simpler way, plus this automatically plays the sound at runtime, not just when I call it.

brap
Aug 23, 2004

Grimey Drawer
Is there a reason you don't use a static method returning Task<MediaElement> which consumes the name of the sound file or something?
In general, it's not good to use async void as opposed to async Task (with no type parameter) because you can't catch any exceptions that get thrown or easily detect that the method has finished running

SmellsLikeToast
Dec 30, 2005

A GREATER MAN THAN I DESERVE
This is the first time I've done any sort of sound functionality at all. I found a better way to implement it by setting the source using the MediaElement object initializer so it's all down to one line of code per sound in the constructor. I just add that to my canvas and it works like a charm. I'm sure that's the quick and dirty way to do things, but it seems to do the trick.

BirdOfPlay
Feb 19, 2012

THUNDERDOME LOSER
I'm working with Unity but I'm having an issue that's pure C# and Mono: I'm catching events from an instance that's not set up right and can't seem to trace where this instance is coming from. The extent of my testing and debugging experience is using breakpoints (which, yes, do work in Unity and MonoDevelop) and want to know what else I could do to squash this bug. Also, I'm liable to be getting some terms wrong with events. I know how to use them but haven't gotten down how to describe and name my methods that operate with them.

I have a combat system, handled by CombatManger, that listens to every unit in the game waiting for the unit to fire it's FoundEnemy event. When that happens, it makes a container class, called Battle, for the two units fighting, and this container also tells each unit when they can attack again. The Battle class also subscribes to both units DeathEvent which fires when the unit has be defeated, which in turn fires an event, called BattleOverEvent, telling the CombatManager that the battle has been completed. The CombatManager then cleans up the battle by removing that Battle instance from it's List of active battles, removing the loser for the game, and checking to see if the victor has any other Battles pending. If the victor does, it resumes that battle. If not, it goes back to walking.

The problem happens after a few battles have been run and completed. At that time the game gets caught in a loop of events where this corrupted Battle fires it's BattleOverEvent. By corrupted, I mean the instance has a reference to the defeated unit and a null reference for the other combatant. The weirdest part of this bug is that I'm not getting a BattleOverEvent from the expected Battle at all, just this corrupted one. I've traced through using break points in the final Make method for Battle, but it's not creating Battles that I don't expect it to. I thought that it might be because of a unit destroying itself before the CombaManager's listener was fired, but I still had this problem after moving destroy method to be called by CombatManager and not in the method that fires the DeathEvent.

The only solution I could come up with to solve this was to unsubscribe to the BattleOverEvent of the completed Battle. It feels kind of hacky, and I'm concerned that this could cause issues with the List of Battles that the CombatManager has. Because I never get the expected Battle, only the corrupted one, I'm worried that the Battle List is not getting culled properly. Specifically, I'm using a simple Remove(Battle) call inside the listener. Is this also a valid concern, that, as the game runs, this list will just become bloated with Battles that don't exist?

Fake edit: Silly thought from typing that out, should I be actively unsubscribing to events when I know I don't need to listen to them any more? I've been under the assumption that would all be handled by the garbage collector when the units get destroyed and leave scope. Granted, that assumption now seems to be false, given that this bug is being cause by destroyed units firing events.

raminasi
Jan 25, 2005

a last drink with no ice

BirdOfPlay posted:

I'm working with Unity but I'm having an issue that's pure C# and Mono: I'm catching events from an instance that's not set up right and can't seem to trace where this instance is coming from. The extent of my testing and debugging experience is using breakpoints (which, yes, do work in Unity and MonoDevelop) and want to know what else I could do to squash this bug. Also, I'm liable to be getting some terms wrong with events. I know how to use them but haven't gotten down how to describe and name my methods that operate with them.

I have a combat system, handled by CombatManger, that listens to every unit in the game waiting for the unit to fire it's FoundEnemy event. When that happens, it makes a container class, called Battle, for the two units fighting, and this container also tells each unit when they can attack again. The Battle class also subscribes to both units DeathEvent which fires when the unit has be defeated, which in turn fires an event, called BattleOverEvent, telling the CombatManager that the battle has been completed. The CombatManager then cleans up the battle by removing that Battle instance from it's List of active battles, removing the loser for the game, and checking to see if the victor has any other Battles pending. If the victor does, it resumes that battle. If not, it goes back to walking.

The problem happens after a few battles have been run and completed. At that time the game gets caught in a loop of events where this corrupted Battle fires it's BattleOverEvent. By corrupted, I mean the instance has a reference to the defeated unit and a null reference for the other combatant. The weirdest part of this bug is that I'm not getting a BattleOverEvent from the expected Battle at all, just this corrupted one. I've traced through using break points in the final Make method for Battle, but it's not creating Battles that I don't expect it to. I thought that it might be because of a unit destroying itself before the CombaManager's listener was fired, but I still had this problem after moving destroy method to be called by CombatManager and not in the method that fires the DeathEvent.

The only solution I could come up with to solve this was to unsubscribe to the BattleOverEvent of the completed Battle. It feels kind of hacky, and I'm concerned that this could cause issues with the List of Battles that the CombatManager has. Because I never get the expected Battle, only the corrupted one, I'm worried that the Battle List is not getting culled properly. Specifically, I'm using a simple Remove(Battle) call inside the listener. Is this also a valid concern, that, as the game runs, this list will just become bloated with Battles that don't exist?

Fake edit: Silly thought from typing that out, should I be actively unsubscribing to events when I know I don't need to listen to them any more? I've been under the assumption that would all be handled by the garbage collector when the units get destroyed and leave scope. Granted, that assumption now seems to be false, given that this bug is being cause by destroyed units firing events.

Does MonoDevelop let you set conditional breakpoints? If so, you can drop a breakpoint in the Battle constructor that only breaks when either of the unit references is null. I'm assuming that that shouldn't happen ever, so you'll only break when the bad Battle is being constructed. Then you can examine the call stack to see where you're going wrong.

(This is under the assumption that Battle participants aren't mutable, which is the impression your description gives, and a good idea, precisely because it makes this type of problem easier to fix. If they aren't mutable, then those fields should be declared readonly so that you don't accidentally mutate them at some point.)

In general, unsubscribing from events you no longer need is a good idea, unless there's a performance reason not to. The main reason to do it is that event subscription creates a reference from the event to the subscriber, which can cause you to keep references around longer than you need. I can't tell from your description whether this is causing your problem, though.

Adbot
ADBOT LOVES YOU

darthbob88
Oct 13, 2011

YOSPOS
Goddammit I hate working with authentication. Why the hell can I not get a refresh token on this project? I've tried adding a RefreshTokenProvider per this page, and a half a dozen others, but still when I make a POST call to the token endpoint, like
code:
jQuery.ajax({
            url: "/Token",
            method: "POST",
            data: $.param({ grant_type: 'password', username: "username", password: "password" }),
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        });
, which worked fine in a previous version of this project, now all I get is a 400 error. Which functions do I still need to include, or is there an existing refresh token provider I can use instead?

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