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
Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



You should be able to take the DLL/EXE the VB project spits out and decompile it as reasonably readable C# with ILSpy if you don't want to put company code through someone else's web server.

Adbot
ADBOT LOVES YOU

ljw1004
Jan 18, 2005

rum

Hammerite posted:

At one point in the code, the VB app calls a method that accepts a String parameter and passes in a Double. Specifically:
Sub XmlTextWriter.WriteString(Text As String)
is being passed the return value of
Function MyClass.MyMethod() As Double

I believe this VB project/file is set to "option strict off". In strict-off mode it allows implicit conversions e.g. from double to string, similar to how Javascript behaves. In strict-on mode it disallows them similar to C#.

The implicit conversion from Double to String is CStr(double) I believe but I'm not sure. The VB spec says "string conversions always consider the current culture of the run-time environment" (so I'm sure the bug you guessed at is there), and also "the precise nature of the conversion is implementation-specific". So I second the suggestion to use reflector to look at the IL. You'll probably find that it calls into a VB-specific helper which embodies all the rules of CStr.

Xik
Mar 10, 2011

Dinosaur Gum

Munkeymon posted:

You should be able to take the DLL/EXE the VB project spits out and decompile it as reasonably readable C# with ILSpy if you don't want to put company code through someone else's web server.

There is also DotPeek which is real easy to use.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
Thanks for all the suggestions. Yes, the project file specifies <OptionStrict>Off</OptionStrict>. I followed the advice to look in ILSpy. It looks like what is actually happening is this:

xmlTextWriter.WriteString(Conversions.ToString(Me.someDateTime.TotalDays))

so the method actually being used to convert is Microsoft.VisualBasic.CompilerServices.Conversions.ToString(double). Unfortunately that documentation doesn't say what conventions are used to convert or whether it uses the user's current culture, but I still suspect that is what it does.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
It looks like it does use CurrentThread.CurrentCulture (or CurrentUICulture, whichever)

code:
Sub Main()
    Dim kEN As String = 2.1
    Console.WriteLine(kEN) REM prints 2.1
    System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR")
    System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR")
    Dim kFR As String = 2.1
    Console.WriteLine(kFR) REM prints 2,1
End Sub

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

ljw1004 posted:

I wrote a bunch of stuff about custom awaiters, and how the compiler expands out the "await" statement. If you read that you'll see that you get complete control over everything, and this will unlock what you need. https://web.archive.org/web/20171014234653/https://blogs.msdn.microsoft.com/lucian/2012/12/11/how-to-write-a-custom-awaiter/

One idiom you might decide to settle on is "await MyAsyncMethod().WithCustomAwaiter()" where you tell the compiler to use your custom machinery at the invocation site.
I was thinking of having custom awaiters trigger a schedule to run other stuff a la tasklets, but I couldn't tell if that would just keep going on the same call stack, which would be very bad.

It's kind of gross to me, but it's looking like if I want to do something like this that I might be best off with good-old-fashioned yield. I was preoccupied with not using it due to the old thing with it taking over the return type, but I am controlling the entire chain here so it's fine if I cram some kind of control container in the IEnumerator for a scheduler to analyze.

Zero The Hero
Jan 7, 2009

Hey guys, I've been messing around with .net core recently, trying out some web stuff. I'm trying to use Identity to manage my logins, sticking to defaults as closely as possible, but I'm getting conflicting advice from Microsoft's docs.

When I start a new project, I can choose to add authentication right then. If I do, it will add a default migration using ApplicationDbContext. It comes with tables for Users, Roles, and more. But the web pages it comes with don't support most of that - they just let you set an email, password, and later, a phone number. There's no user model created. On the other hand, if you go through Add -> New Scaffolded Item, you get a lot more options, with the pages (razor pages :( ) to support them, as well as a user model already defined for you. You can opt to put all this in its own context so it isn't shared with your application context. But... no roles. And it's not compatible with the system added when you choose authentication during project creation. So you end up with two separate Identity implementations, neither one complete, in my opinion.

It's not that I can't do this at all on my own, but I am trying to use their system wherever possible. Their role system is a lot more robust than mine would be, and (I assume) compatible with their [Authorize(roles="...")] annotation. I feel like I'm just missing something here. And while the documentation has a ton of info, it isn't always consistent. One article will be written assuming the Identity pages are MVC, and the next will assume they're razor pages. Anyone know where I should go next?

LongSack
Jan 17, 2003

It seems that in WPF the TextBox.SelectAll method does not work, or at least does not work reliably. I have a TextBox used for searching. I want the text in the box to be selected when the box gets focus, since it's most likely that the new search will be different than the last.

I have tried handling the GotFocus event in code-behind. I've tried registering a class handler for the event in the OnStartup method in my App class (which should handle it for all text boxes) using something like this:
C# code:
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (!(object is TextBox tb))
        return;
    tb.SelectAll();
}
Neither worked.

I even coded a custom control:
C# code:
public class FocusingTextBox : TextBox
{
    static FocusingTextBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(FocusingTextBox), new FrameworkPropertyMetadata(typeof(FocusingTextBox)));
    }

    public static readonly DependencyProperty SelectAllOnFocusProperty = DependencyProperty.Register("SelectAllOnFocus",
        typeof(bool), typeof(FocusingTextBox), new PropertyMetadata(false));

    public bool SelectAllOnFocus
    {
        get => (bool)GetValue(SelectAllOnFocusProperty);
        set => SetValue(SelectAllOnFocusProperty, value);
    }

    protected override void OnGotFocus(RoutedEventArgs e)
    {
        Debug.WriteLine($"FocusingTextBox.OnGotFocus called, SelectAllOnFocus={SelectAllOnFocus}");
        base.OnGotFocus(e);
        if (SelectAllOnFocus)
        {
            SelectAll();
        }
    }
}
Still doesn't work. The Debug shows that the method is being called and that SelectAllOnFocus is set to true.

The most infuriating thing is that every once in a great while, it will work.

This shouldn't be this hard. Any ideas?

NihilCredo
Jun 6, 2011

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

I assume you've tried these? First search result for "wpf textbox selectall":

https://stackoverflow.com/questions/660554/how-to-automatically-select-all-text-on-focus-in-wpf-textbox

LongSack
Jan 17, 2003


Oddly, I didn't come across that answer, probably because I was searching on "selectall not working". I'll give it a try, thanks. I still think that SelectAll in a GotFocus event should work.

putin is a cunt
Apr 5, 2007

BOY DO I SURE ENJOY TRASH. THERE'S NOTHING MORE I LOVE THAN TO SIT DOWN IN FRONT OF THE BIG SCREEN AND EAT A BIIIIG STEAMY BOWL OF SHIT. WARNER BROS CAN COME OVER TO MY HOUSE AND ASSFUCK MY MOM WHILE I WATCH AND I WOULD CERTIFY IT FRESH, NO QUESTION
Is anyone here using the latest AutoMapper with SimpleInjector? I can't for the life of me get SimpleInjector to inject an initialised instance of IMapper. It used to work but I just cannot get it to work on this latest version. My Startup.cs:
C# code:
public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

private readonly Container container = new Container();
public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddAutoMapper();

    IntegrateSimpleInjector(services);
}

private void IntegrateSimpleInjector(IServiceCollection services)
{
    container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

    services.AddHttpContextAccessor();

    services.AddSingleton<IControllerActivator>(new SimpleInjectorControllerActivator(container));
    services.AddSingleton<IViewComponentActivator>(new SimpleInjectorViewComponentActivator(container));

    services.EnableSimpleInjectorCrossWiring(container);
    services.UseSimpleInjectorAspNetRequestScoping(container);
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    InitialiseContainer(app);

    app.UseMvc();
}

private void InitialiseContainer(IApplicationBuilder app)
{
    container.RegisterMvcControllers(app);
    container.RegisterMvcViewComponents(app);

    container.Register(typeof(IQueryHandler<,>), typeof(IQueryHandler<,>).Assembly);
    container.Register(typeof(ICommandHandler<>), typeof(ICommandHandler<>).Assembly);

    container.AutoCrossWireAspNetComponents(app);
}
Then in one of my IQueryHandlers I'm attempting to inject IMapper, but it keeps telling me the mapper is not initialised. I cannot figure this out at all and it's driving me insane. I'm 99% sure this is going to be a scoping issue, but I can't work it out.

Edit: nvm, found the issue and it was completed loving stupid.

putin is a cunt fucked around with this message at 07:28 on Apr 16, 2019

LongSack
Jan 17, 2003

Is there a good reason why static classes can’t implement an interface? I have an instance where I’d love to declare a constructor as
C# code:
public ImportViewModel<T>(List<T> existing, string description, IDataAccessLayer DAL)
but since my DAL classes are all static, they can’t implement the interface. So instead, I have to do
C# code:
public ImportViewModel<T>(List<T> existing, string description, Type dalType)
and use reflection.

It works, but interfaces would be better.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

LongSack posted:

Is there a good reason why static classes can’t implement an interface? I have an instance where I’d love to declare a constructor as
C# code:
public ImportViewModel<T>(List<T> existing, string description, IDataAccessLayer DAL)
but since my DAL classes are all static, they can’t implement the interface. So instead, I have to do
C# code:
public ImportViewModel<T>(List<T> existing, string description, Type dalType)
and use reflection.

It works, but interfaces would be better.

Because you can't instantiate a static class, so what would an interface provide? An interface is a contract that says what methods an instance of a class is capable of providing.

Data access classes shouldn't be static. How do you unit test the code that calls them?

LongSack
Jan 17, 2003

New Yorp New Yorp posted:

Because you can't instantiate a static class, so what would an interface provide? An interface is a contract that says what methods an instance of a class is capable of providing.

Data access classes shouldn't be static. How do you unit test the code that calls them?

Interfaces are code contracts, so why shouldn’t static classes be able to provide methods that adhere to those contracts?

edit: what I’m looking for is something like
C# code:
public interface IDataAccessLayer<T>
{
    int Insert(T obj);
    void Update(T obj);
    void Delete(T obj);
    List<T> Get();
    T Read(int id);
}

LongSack fucked around with this message at 04:49 on Apr 17, 2019

rarbatrol
Apr 17, 2011

Hurt//maim//kill.

LongSack posted:

Interfaces are code contracts, so why shouldn’t static classes be able to provide methods that adhere to those contracts?

The big reason being you can't swap out a static class for another implementation of the interface it implements - it's static. You could, however, have a static reference to an implementation of the interface, which can then be changed.

LongSack
Jan 17, 2003

rarbatrol posted:

The big reason being you can't swap out a static class for another implementation of the interface it implements - it's static. You could, however, have a static reference to an implementation of the interface, which can then be changed.

Ok, this makes sense. I guess I’ll continue to use reflection :yeah:

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

LongSack posted:

Interfaces are code contracts, so why shouldn’t static classes be able to provide methods that adhere to those contracts?

Let's say you have a theroetical static interface:
code:
public static interface IFoo 
{
  public static void DoSomething();
}

public static class Bar : IFoo { /*implementation*/ }
public static class Baz : IFoo { /* different implementation*/ }
If you want to call a method in Bar, you write Bar.Dosomething(). If you want to call a method in Baz, you write Baz.Dosomething(). If you want to, in some cases, call a method in Bar, and in others, call a method in Baz, how do you write that?

There are good solutions to this problem in the language already:
1) Use non-static classes with instance methods, which allow you to implement inversion of control, which is exactly what you seem to be wanting to accomplish here
2) Use generics

More reading:
https://stackoverflow.com/questions/259026/why-doesnt-c-sharp-allow-static-methods-to-implement-an-interface

[edit]
C# code:
public interface IDataAccessLayer<T>
{
    int Insert(T obj);
    void Update(T obj);
    void Delete(T obj);
    List<T> Get();
    T Read(int id);
}
This is incredibly common in the repository pattern, which almost universally achieves this with abstract classes and interfaces without anything needing to be static.

Reflection is an awful workaround to what appears to be a poor design choice.

New Yorp New Yorp fucked around with this message at 05:03 on Apr 17, 2019

EssOEss
Oct 23, 2006
128-bit approved

LongSack posted:

Ok, this makes sense. I guess I’ll continue to use reflection :yeah:

The right answer is "I guess I'll stop using static classes"

NihilCredo
Jun 6, 2011

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

New Yorp New Yorp posted:

Let's say you have a theroetical static interface:
code:
public static interface IFoo 
{
  public static void DoSomething();
}

public static class Bar : IFoo { /*implementation*/ }
public static class Baz : IFoo { /* different implementation*/ }
If you want to call a method in Bar, you write Bar.Dosomething(). If you want to call a method in Baz, you write Baz.Dosomething(). If you want to, in some cases, call a method in Bar, and in others, call a method in Baz, how do you write that?

I don't see why that would be ambiguous in any way:

code:
public void UseFoo(IFoo foo)
{
  foo.DoSomething();
}

public void Main(string[] args)
{
    if(args[0] == "fart") { 
      UseFoo(Bar);
    } else {
      UseFoo(Baz);
    };
}
IIRC, Eric Lippert even said that there was no technical reason they couldn't do it, it would just have been a pain and a lot of work to implement.


To LongSack: I agree with the others that making the class non-static (even if it doesn't have any fields) is the easiest and least painful solution.

There are some alternatives that are safer than reflection (e.g. use a 'bag of lambdas' class as a pseudo-interface) but they're somewhat verbose and extremely non-idiomatic.

B-Nasty
May 25, 2005

New Yorp New Yorp posted:

1) Use non-static classes with instance methods, which allow you to implement inversion of control, which is exactly what you seem to be wanting to accomplish here

This is the right answer.

Also, couple this with a DI container that can handle registering open generics (any of them worth discussing), and you don't have to think about it. With SimpleInjector it would be one line of code:

code:
container.Register(typeof(IDataAccessLayer<>), typeof(IDataAccessLayer<>).Assembly);
Then you just allow it to inject the implementation of the DAL for a given type;

code:
public class MyWorker{
	public MyWorker(IDataAccessLayer<Foo> fooDal, IDataAccessLayer<Bar> barDal, ...){
		this.fooDal=fooDal;
		this.barDal=barDal;
		...
	}
}

NihilCredo
Jun 6, 2011

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

Dissenting opinion: please avoid using DI containers as long as you can.

DI is very good, always. DI containers are not, usually. Unless your project goes absolutely crazy with dependency chains, it will be quicker to write a factory class with GetThingy() methods, and you will retain compile-time safety.

Volguus
Mar 3, 2009

NihilCredo posted:

Dissenting opinion: please avoid using DI containers as long as you can.

DI is very good, always. DI containers are not, usually. Unless your project goes absolutely crazy with dependency chains, it will be quicker to write a factory class with GetThingy() methods, and you will retain compile-time safety.

Unless there's something wrong with DI containers in .NET or with your choice of a container specifically or you have very weird requirements that somehow a DI container would break, one should never go down to manage dependency injection and component's lifetime manually. Life's too short for that kind of crap.

B-Nasty
May 25, 2005

NihilCredo posted:

DI containers are not, usually.

Disagree, strongly.

Can there be foot-guns, sure, but if you take more of a 'convention over config' approach (e.g. auto wire implementations matching the interface name) and use a container that supports testing that all dependencies are wired on startup (e.g. Structuremap's AssertConfigurationIsValid()), you avoid the biggest issues. I'm not writing an inter-connected web of Factory classes sprinkled all around when I can have all the dependency configuration stuff contained in my composition root.

ASP.NET Core stuff has a builtin DI container, so you're needlessly swimming against the current if you are still in Factory land.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

NihilCredo posted:

Dissenting opinion: please avoid using DI containers as long as you can.

DI is very good, always. DI containers are not, usually. Unless your project goes absolutely crazy with dependency chains, it will be quicker to write a factory class with GetThingy() methods, and you will retain compile-time safety.

I generally agree but this is a horse that's been beaten to death, I think even in this thread, in the past few months.

NihilCredo
Jun 6, 2011

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

New Yorp New Yorp posted:

I generally agree but this is a horse that's been beaten to death, I think even in this thread, in the past few months.

Oh sure. I don't expect to change people's mind in a few posts, especially if they've been using DI without any problem for years; I just don't want LongSack to think that 'use a DI container' is on the same level of universally-agreed-upon as 'use interfaces instead of reflection'.

B-Nasty posted:

Disagree, strongly.

Can there be foot-guns, sure, but if you take more of a 'convention over config' approach (e.g. auto wire implementations matching the interface name) and use a container that supports testing that all dependencies are wired on startup (e.g. Structuremap's AssertConfigurationIsValid()), you avoid the biggest issues. I'm not writing an inter-connected web of Factory classes sprinkled all around when I can have all the dependency configuration stuff contained in my composition root.

ASP.NET Core stuff has a builtin DI container, so you're needlessly swimming against the current if you are still in Factory land.

Well, I happen to think 'convention over configuration' is a footgun in the waiting, if the convention isn't sufficiently verified at compile time. (Verification at startup isn't nearly as good as verification at compile time.)

The builtin DI container for ASP.NET Core is the one that decided to silently spit a null at me when it failed to understand a type parameter, and made me waste quite a lot of time because it was the last place where I thought there could be a the problem, exactly because it looked so straightforward. The reason it failed was extremely arcane and I cannot fault the ASP.NET team for not foreseeing it, so I took it as a broader lesson: don't do at runtime what you could be doing at compile-time, if it's at all feasible. And (I think this is where we disagree) writing a simple composition root is feasible, quick and straightforward in modern .NET.

NihilCredo fucked around with this message at 17:53 on Apr 17, 2019

rarbatrol
Apr 17, 2011

Hurt//maim//kill.

NihilCredo posted:

Dissenting opinion: please avoid using DI containers as long as you can.

DI is very good, always. DI containers are not, usually. Unless your project goes absolutely crazy with dependency chains, it will be quicker to write a factory class with GetThingy() methods, and you will retain compile-time safety.

I'm more or less re-writing a legacy "cleanup job " feature and it consists of ~5 similar but distinct stages. Each of these stages is now essentially the (poor man's) composition root of a number of common behaviors/data sources/error handlers and I'm really happy with how it's all shaping up. Is it a lot more plumbing code than if I used a DI container? Totally. But it's also supremely easy to tell what each one does and at a glance, and how they differ from each other.

Space Whale
Nov 6, 2014
So I have a C# scaling question that comes from finding code that, when read, makes you hear Rachmaninoff's C# minor prelude from inside of your own head.

Basically, years ago, someone wrote a job runner service, and a service...service. When the job runner got a request, it'd just spin up a thread. Every time. Every call. No management of threads in any way, no pooling - no TPL - nothing. The service-service also uses a thread to call the job runner service when it's not called directly. The cherry on top is sometimes you have to iterate over options or temperature degrees, and each of them is YET ANOTHER THREAD, not just a loop. Because.

As you can imagine, the server running this is fine with low volume, but the second a big batch of poo poo to do comes in, it just pegs out for an hour or an hour and a half. I went to just ripping that bullshit out and I'm wondering "so how DOES iis actually scale poo poo?"

Also, the loving winner winner chicken dinner is how another service waits on the pegged out job runner:

code:
RetryRequest:
            try
            {
                jsonResponse = serviceWorker.SendServiceRequest<GenerateAnalysisRequest, GenerateAnalysisResponse>(Config.JOBRUNNERServiceUrl, JsonRequest, "GenerateAnalysis", timeout, false);
                //Update server cache
            }
            catch (Exception ex)
            {
                //If failure is due to no capacity, loop back 10 times, unless the job has been made to fail by the calling job queue.

                if ((ex.Message.ToLower().Contains("timed out") ||
                    ex.Message.ToLower().Contains("outofmemory") ||
                    ex.Message.Contains("503") ||
                    ex.Message.Contains("504") ||
                    ex.Message.ToLower().Contains("responding")) && loopCount < Config.JobRunnerAnalysisServiceRetryCount)
                {
                    timeout = 5000; //reduce to 5 seconds on subsequent calls
                    loopCount = loopCount + 1;

                    //Wait a few seconds
                    new System.Threading.ManualResetEvent(false).WaitOne(ServiceContext.RunAnalysisInBackground ? Config.JobRunnerAnalysisServiceRetryWaitTimeQueued : Config.JobRunnerAnalysisServiceRetryWaitTimeDirect);
                    goto RetryRequest;
                }

               
            }

            HttpRuntime.Cache.Insert(
                $"{JsonRequest.JobId}_Analysis",
                jsonResponse,
                null,
                DateTime.UtcNow.AddMinutes(Config.MaxJobQueueTime >= Config.MaxJobDirectTime ? Config.MaxJobQueueTime : Config.MaxJobDirectTime),
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.High,
                null);
A goto loop using a try-catch. Also WTF is that httpruntime poo poo? Wow.

Anyway, this is why we have code reviews.

Mr Shiny Pants
Nov 12, 2012
I have a server running inside Unity that is written in F# that accepts connections and fires an event that gets handled in the game.
This works fine when I don't need to return any data but, guess you could see this coming, now I do need to return some data.

The way I handle it is with a ref value that gets sent in the eventargs, I fill the data in the engine thread and I pattern match on the ref value inside the webserver thread to handle it.
It works as expected, I was just wondering if this is a smart way of doing this or if I am opening myself up to all sorts of crazy errors.

Like:
code:
            | {Method = "GET"; Url = [|"session"|]} ->
                let info = ref<SessionInfo option> None
                do event.Trigger(Session info)
                match !info with
                | Some sessionInfo ->
                    jsonOutputRoute context sessionInfo
                    
                | None ->
                    errorRoute context "No session info found"   
Inside Unity:
code:
            case Types.Command.Tags.Session:
                print("Session info command received");
                var info = args as Types.Command.Session;
                if (State.CurrentPlayer != null)
                {
                    print("Player is not null");
                    var ses = Microsoft.FSharp.Core.FSharpOption<Types.SessionInfo>.Some(new Types.SessionInfo(State.CurrentPlayer.Id, State.CurrentPlayer.Name, State.CurrentPlayer.Time));
                    info.Item.Value = ses;
                    
                }
                break;

Mr Shiny Pants fucked around with this message at 13:39 on Apr 24, 2019

NihilCredo
Jun 6, 2011

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

Mr Shiny Pants posted:

The way I handle it is with a ref value that gets sent in the eventargs, I fill the data in the engine thread and I pattern match on the ref value inside the webserver thread to handle it.
It works as expected, I was just wondering if this is a smart way of doing this or if I am opening myself up to all sorts of crazy errors.

Mechanically it will work just fine - "I raised an event" is just sugar for "I have a public list of same-signature lambdas to which anyone can add their own, and I call each one in turn".

The reason ref event arguments are a bad, baaaad idea is because by design you have zero control over who subscribes to the event and, just as importantly, in what order their handlers are called. Likewise the handlers cannot see each other and know who got called first, except by checking and interpreting the content the ref argument.

So if it's a one-off and you're OK with manually enforcing the rule that one and only one handler should subscribe to that event, you'll be fine. If you're gonna have to repeat the pattern and risk losing track of which event is being handled by how many handlers, find a way now to pass to the F# server a reference to a unit -> SessionInfo function it can call when needed (which you can later expand if necessary into a IGameInfoProvider interface or something).

Edit: Come to think of it, you could separate the "backflow" from the events with a couple lines of code. It would be barely any safer than the event handler route, but it would convey intent much better:

code:
type Server() =

  member val GetSessionInfo : unit -> SessionInfo option = (fun () -> None) with get, set

  // etc.
 | {Method = "GET"; Url = [|"session"|]} ->
     let info = this.GetSessionInfo()
     do event.Trigger() // if you still need this for other reasons
  // etc.
code:

  server.SomeEvent += SomeHandler;
  // add this:
  server.GetSessionInfo = (
     () => if (State.CurrentPlayer != null)
                {
                    print("Player is not null");
                    return Microsoft.FSharp.Core.FSharpOption<Types.SessionInfo>.Some(new Types.SessionInfo(State.CurrentPlayer.Id, State.CurrentPlayer.Name, State.CurrentPlayer.Time));
                    
                } else { return Microsoft.FSharp.Core.FSharpOption<Types.SessionInfo>.None; }
   );

NihilCredo fucked around with this message at 19:29 on Apr 24, 2019

Mr Shiny Pants
Nov 12, 2012
I read about the last registered handler will set the value and other funky stuff that happens with events and handlers. The way it is built now there is just one handler and it will only ever be this one handler, so that should not be a problem.
The problem is that in the current setup the other scripts have no reference to the server and subscribing to events was the easy way of wiring it all together without needing to re-architect a whole load off stuff. This has to do with scripts and variables existing in a scene that get destroyed when you reload the scene.

I was just wondering if there might be some hidden race conditions or some other shared-state shenanigans hiding in the code I posted.

I am probably overthinking this, but my original idea was to have something like a callback like function getting sent out into the engine, do its things and on return, handle the rest of the request.


Let's see if I can explain this better:
The server part is just a loop that runs continuously on a background thread using an Async workflow, I created an F# type that gets instantiated in a singleton ( yes, I know ) within Unity that saves info that needs to stay resident even if the Scene gets destroyed. The F# type creates a recursive function that waits for connections.
Now the part I am struggling with is that the server gets an request and it "flows" from connect to disconnect inside the F# type. Unity does not know anything about handling requests and whatnot and using an event I can just "break" into the main gameloop when needed and do some processing.

Using the ref type I can just write my connection handler the way I always write them within the F# type: accept -> do something -> return Ok or Error. Compile my DLL, copy it into the Assets folder and it works.

So conceptually, in my mind at least, I have two worlds as it were: the main game loop and the webserver loop. And both react to input, from joysticks or an http request.

How would you write something like this? What I would have loved was something like Async.FromBeginEnd(GetDataFromEngineBegin, GetDataFromEngineEnd) in the server but I have no idea how to write something like this, not yet at least.

I hope this makes sense. :)





Mr Shiny Pants fucked around with this message at 08:06 on Apr 25, 2019

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
Has anyone been doing anything heavier-weight than "Hello world!"-type stuff with Blazor? I just sat down with it last weekend for an hour and I'm beyond overjoyed at the prospect of abandoning JavaScript on the front end.

User0015
Nov 24, 2007

Please don't talk about your sexuality unless it serves the ~narrative~!

New Yorp New Yorp posted:

Has anyone been doing anything heavier-weight than "Hello world!"-type stuff with Blazor? I just sat down with it last weekend for an hour and I'm beyond overjoyed at the prospect of abandoning JavaScript on the front end.

Having just came home today after trying to wrangle angularjs into doing what should be the simplest of things but is instead a labyrinthine nightmare of lifecycle binding child/parent relationship bullshit, I want to know more about this too.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



I'm waiting for Core 3 to come out of preview to try Blazor because I avoid Preview versions because previews used to occasionally break stuff when you tried to remove them to use the release version :ohdear:

Really want to try it, though.

Mr Shiny Pants
Nov 12, 2012
You could try Fable if you want to write a strongly typed language that gets compiled down to JS.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



What I want is a slick way to more-or-less port a bunch of existing CSHTML into a SPA

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Started using .net core 2.1 ... really liking the System.Memory stuff
code:

public IPAddress (ReadOnlySpan<byte> address);
code:
public static long BitConverter.ToInt64 (ReadOnlySpan<byte> value);
:eyepop:

NihilCredo
Jun 6, 2011

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

Mr Shiny Pants posted:

Let's see if I can explain this better:
The server part is just a loop that runs continuously on a background thread using an Async workflow, I created an F# type that gets instantiated in a singleton ( yes, I know ) within Unity that saves info that needs to stay resident even if the Scene gets destroyed. The F# type creates a recursive function that waits for connections.
Now the part I am struggling with is that the server gets an request and it "flows" from connect to disconnect inside the F# type. Unity does not know anything about handling requests and whatnot and using an event I can just "break" into the main gameloop when needed and do some processing.

Using the ref type I can just write my connection handler the way I always write them within the F# type: accept -> do something -> return Ok or Error. Compile my DLL, copy it into the Assets folder and it works.

So conceptually, in my mind at least, I have two worlds as it were: the main game loop and the webserver loop. And both react to input, from joysticks or an http request.

How would you write something like this? What I would have loved was something like Async.FromBeginEnd(GetDataFromEngineBegin, GetDataFromEngineEnd) in the server but I have no idea how to write something like this, not yet at least.

I hope this makes sense. :)

I am totally unfamiliar with Unity, but from your summary it sounds like you're having a classic cyclic dependency problem, with the HTTP server and the Unity scenes depending on each other, where the server is fixed but the scenes get destroyed and replaced over time. So you're finding it messy to manage who calls whom at which times.

The solution ought to lie in making the dependencies linear, e.g. by extracting whatever common types and interfaces need to be shared into a module that gets placed at the bottom of the load order, and then writing a composition root that ensures everybody has a reference to everything they need at startup.

Is it possible in Unity to write a unit -> UnityEngine.Scene option function that returns whatever the current Scene is (if there is one)? If so, you could create such a function, Option.map the resulting UnityEngine.Scene to the bottom-of-the-load-order interface type, and then pass this lambda function to the HTTP server on instantiation so it can access whatever it needs.

Mr Shiny Pants
Nov 12, 2012

NihilCredo posted:

I am totally unfamiliar with Unity, but from your summary it sounds like you're having a classic cyclic dependency problem, with the HTTP server and the Unity scenes depending on each other, where the server is fixed but the scenes get destroyed and replaced over time. So you're finding it messy to manage who calls whom at which times.

The solution ought to lie in making the dependencies linear, e.g. by extracting whatever common types and interfaces need to be shared into a module that gets placed at the bottom of the load order, and then writing a composition root that ensures everybody has a reference to everything they need at startup.

Is it possible in Unity to write a unit -> UnityEngine.Scene option function that returns whatever the current Scene is (if there is one)? If so, you could create such a function, Option.map the resulting UnityEngine.Scene to the bottom-of-the-load-order interface type, and then pass this lambda function to the HTTP server on instantiation so it can access whatever it needs.

I see what you mean, I think.

I could write an IGameStateInfo interface in the Scene scripts that returns an SessionInfo object and have the rootobject set this inside server component. Whenever I need the info I can just call the function on the interface.

I'll mull this over some more, I like your function idea better though. Thanks.

nielsm
Jun 1, 2009



I have a .NET Framework 4.7 program which runs in the background with no forms (it has some invisible windows for Win32 messages) which appears to be crashing silently at random. It may run a full day without problems, or it may crash after a minutes. I haven't noticed a pattern yet and have no idea where to begin debugging. Any suggestions for how to capture some backtraces, minidumps, or anything else useful?

Adbot
ADBOT LOVES YOU

Roid666
Jul 18, 2010
Is there anything in event viewer?

Hopefully that'll have something useful,else add in logging to a file (e.g using log4net), which should hopefully give you some idea where it's getting to before crashing.

What does your error handling look like?

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