|
Hi,
Why Sample #2 is "Bets Practices". Second sample include "await" keyword on the same line with Async Method. Both codes are blocking Thread. Any idea? thanks...
Sample #1
var products = _context.Products.ToList();
Sample #2
var products = await _context.Products.ToListAsync();
|
|
|
|
|
It gets a complicated, but basically the await call spins off a second thread to execute the long running task, and effectively suspends the method until it's complete. But ... the thread that executed await can continue as if the method had finished.
This is handy if you want to run a long task from the main (UI) thread while the UI remains responsive.
For example, if you run this code:
private void MyOtherButton_Click(object sender, EventArgs e)
{
Debug.WriteLine("Before Sleep");
Thread.Sleep(10000);
Debug.WriteLine("After Sleep");
}
Your console will print "Before Sleep", wait ten seconds and print "After Sleep" - but your user can't do anything else with your app in the mean time.
But this code:
private async void MyOtherButton_Click(object sender, EventArgs e)
{
Debug.WriteLine("Before Sleep");
await Task.Run(() => Thread.Sleep(10000));
Debug.WriteLine("After Sleep");
}
Prints the same things, but your user can carry on working - your UI remains working.
Have a look here: https://www.pluralsight.com/guides/understand-control-flow-async-await[^] - it explains it pretty well, and shows examples.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
OriginalGriff wrote: the await call spins off a second thread to execute the long running task
A common misconception.
await is almost nothing to do with multi-threading; it's more about using IO-completion ports to avoid keeping a thread spinning whilst it waits for an external resource to respond.
OriginalGriff wrote:
private async void MyOtherButton_Click(object sender, EventArgs e)
{
Debug.WriteLine("Before Sleep");
await Task.Run(() => Thread.Sleep(10000));
Debug.WriteLine("After Sleep");
} Aside from the fact that you should avoid async void wherever possible[^], spinning up a background thread just to make it sleep seems like a bad idea.
private void MyOtherButton_Click(object sender, EventArgs e)
{
_ = MyOtherButton_Click_Async();
}
private async Task MyOtherButton_Click_Async()
{
Debug.WriteLine("Before Sleep");
await Task.Delay(10000);
Debug.WriteLine("After Sleep");
} See David Fowler's explanation of the _ = SomeTaskReturningMethod(); construct under the "Timer callbacks" heading: AspNetCoreDiagnosticScenarios/AsyncGuidance.md at master · davidfowl/AspNetCoreDiagnosticScenarios · GitHub[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
modified 20-Sep-22 11:11am.
|
|
|
|
|
The second code example doesn't block the thread; it blocks the rest of the method until the call has completed. The low-level thread is freed up to deal with other work until the ToListAsync call completes.
Think of it like a car journey: in the first sample, your kids (the thread) spend the whole time yelling "Are we there yet? Are we there yet? Are we there yet?" until you reach your destination; with the second sample, they get on with reading a book quietly until you tell them you've arrived. One of those scenarios makes for a much nicer journey.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
A beautiful example, thank you for that.
I’ve given up trying to be calm. However, I am open to feeling slightly less agitated.
|
|
|
|
|
I got my answer, thanks.
I have one more question. You said "it blocks the rest of the method" yes the following codes will not be executed until the job is complete, what exactly is waiting here? I guess it was a deep question
|
|
|
|
|
Behind the scenes, your async method will be rewritten into a state machine. Whenever you await something, so long as that operation doesn't complete immediately, the rest of your method will be signed up as a "continuation" to run when that asynchronous operation completes.
As a simple example:
public async Task Foo()
{
Console.WriteLine("Start...");
await Task.Delay(1000);
Console.WriteLine("Done.");
} would (logically) turn into something more like:
public Task Foo()
{
Console.WriteLine("Start...");
return Task.Delay(1000).ContinueWith(_ => Console.WriteLine("Done."));
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
Hello there!
I am new to this forum and I am also a beginner C# coder. I am trying to make a paid app but I will need to make a license key system. Do anyone know any tutorials I can use for this?
It should check the Realtime DB for the license key and check get the processor ID (or any other unique identifier) then it will check your device for the unique id and boom! you are in.
Or if there are any other tutorials please do link them in the comments below thanks!
|
|
|
|
|
|
I'm working on an ASP.NET Core web API and SQLite database. I have created a table for users of my application. The rule is that each user can send a message to some other users (creating White-List). I use the following model for Users:
public class UserModel
{
[Key]
public int UserID { get; set; }
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Role { get; set; }
public Department Department { get; set; }
}
My desired table is:
User-SubUser table
------------------------------------
UserID ReceiverUserID
------ --------------
23 11
42 11
19 -
34 23
Note that the IDs mentioned above are the UserIDs from the User table. This table says that users 23 and 42 can send a message to user 11, user 34 can send a message to user 23, and user 19 cannot send message to anyone.
How can I make a model for creating such a table?
|
|
|
|
|
Having "19" in the table is pointless and just complicates the situation.
The simplest "model" is to simply join "Users" and "User-SubUser" when you need to; e.g. who can x send to (join on UserID), or who might x receive from (join on ReceiverUserID).
If you want the (database) server to maintain "referential integrity", that's another story.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Ok, Considering the final table only includes pairs (removing 19), how can I do joining using C# and EF Core?
|
|
|
|
|
Your "vehicle" in this case is LINQ.
Complex Query Operators - EF Core | Microsoft Docs
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
I meant how I can create a UserSubUser table. I need a C# model to create this table (Code-First approach). UserIDs in the UserSubUser table should be linked to the UserModel table.
|
|
|
|
|
No, they don't. You need to look up normalization, and apply dem rules to your database.
If all that is required is whitelisting, then just have a table with users who are allowed to message each other. You think from C#; but the layer your working in is SQL, where you need to think SQL. Normalize them tables, work from there.
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
|
I've finished an application in C# using Visual Studio 2022 and need to make an installer for it. I used Microsoft Visual Studio Installer Projects extension and could create the installer which works fine. But I need something else: during instalation, it's necessary to create a folder, then a file and save this file into that folder. But I don't know how to do this in this installer. Does anybody has a solution for this? Thanks.
|
|
|
|
|
Your app should be able to create a folder and file; there's no reason for an installer to do it as you describe it ("the install works fine").
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
C# you try it's remain a fewer ways for you
|
|
|
|
|
I want to create a memory stream as follows
[1byte][4bytes][n bytes][4 bytes][n bytes][4 bytes][n bytes] ....ect
my first stream consisted of [0][12][Hello World.]
_packetWriter.WriteOpCode((byte)opCode);
_packetWriter.WriteMessage("Hello World.");
_client.Client.Send(_packetWriter.GetPacketBytes());
when I read it back I get the following, and when I look at the byte arrays I'm seeing some bytes from the previous chunk
10/09/2022 11:39:00 : Opcode Found With Value 0
10/09/2022 11:39:00 : Chunk Found With Value 12
10/09/2022 11:39:00 : Message Found With Value
Hello Worl
can anybody help
thanks madaxe
public class PacketWriter : BinaryWriter
{
public MemoryStream MemoryStream;
public BinaryWriter BinaryWriter;
public PacketWriter()
{
MemoryStream = new MemoryStream();
BinaryWriter = new BinaryWriter(MemoryStream);
}
public void WriteOpCode(byte opCode)
{
MemoryStream.WriteByte(opCode);
}
public void WriteNextChunckSize(int chunkSize)
{
BinaryWriter.Write((Int32)chunkSize);
}
public void WriteMessage(string message)
{
WriteNextChunckSize(message.Length);
BinaryWriter.Write(message);
}
public byte[] GetPacketBytes()
{
return MemoryStream.ToArray();
}
}
public class PacketReader : BinaryReader
{
private NetworkStream _memoryStream;
public PacketReader(NetworkStream memoryStream) : base(memoryStream)
{
_memoryStream = memoryStream;
}
public int ReadOpCode()
{
return _memoryStream.ReadByte();
}
public string ReadMessage(int chunkSize)
{
byte[] readMessage;
readMessage = new byte[chunkSize];
_memoryStream.Read(readMessage, 0, chunkSize);
var message = Encoding.ASCII.GetString(readMessage);
return message;
}
public int ReadChunkSize()
{
byte[] readChunkSize;
readChunkSize = new byte[4];
_memoryStream.Read(readChunkSize, 0, 3);
return BitConverter.ToInt32(readChunkSize, 0);
}
}
|
|
|
|
|
BinaryWriter.Write(string) writes a length-preceded string to the stream, with the length encoded as a variable-length integer (7 bits per block and a continuation bit). So some extra stuff appeared in your stream that you didn't count on.
BinaryWriter.Write(string) is most easily "mirrored" by using BinaryReader.ReadString in the decoder. Of course, you can also handle the length manually, but then you should probably also handle the encoding and write raw bytes to the stream to start with.
This is also wrong: _memoryStream.Read(readChunkSize, 0, 3); reading 3 bytes instead of 4. Why not use BinaryReader , it's simpler and less error prone.
By having written one extra byte per mistake (the extra length byte that BinaryWriter.Write(string) wrote, could have been more bytes for longer strings) and by having read one byte too few, a two byte discrepancy was created. Actually you should find that there are two unprintable characters at the start of your string, since it still should be 12 bytes, just not quite the right 12 bytes.
|
|
|
|
|
sure enough _memoryStream.Read(readChunkSize, 0, 4); fixed part of the problem and also changing the Write message as below fixed the issue.
but I want to use BinaryReader since I'm using BinaryWriter
the behavior I'm seeing is I can consecutively call ReadByte and it will read each byte in turn without me having to define position within the stream, which I don't understand.
so how do is use BinaryReader to read specific blocks of bytes, 2->6, and 7->19
thanks
Madaxe
public void WriteMessage(string message)
{
WriteNextChunckSize(message.Length);
byte[] byteArray = Encoding.UTF8.GetBytes(message);
BinaryWriter.Write(byteArray);
}
|
|
|
|
|
You can do some dummy reads of suitable sizes, discard the results, and then call the suitable Read method when the position of the stream is at the intended location. Or you can set the position of the underlying stream directly, and then read with the BinaryReader. Unfortunately both of these feel a bit like a hack, IMO there should have been some method on BinaryReader to skip a number of bytes, but that doesn't exist.
|
|
|
|
|
Hello,
I have a problem with a self programmed windows service for .Net 6 that inherits from BackgroundService:
namespace WooComMesserschmidt
{
internal class Worker : BackgroundService
{
private readonly HttpClient Client = new()
private string BaseAddress = string.Empty;
private readonly IConfiguration Configuration;
private string ConfigFile = string.Empty;
private readonly Dictionary<string, dynamic?> _ConfigPar;
internal static Dictionary<string, string> ConfigPar = new();
private readonly ILogger<Worker> _logger;
public struct LogInfo
{
public ILogger<Worker>? Logger;
public string? LogFile;
public LogInfo(ILogger<Worker>? logger, string logfile)
{
Logger = logger;
LogFile = logfile;
}
}
public static LogInfo logInfo;
public Worker(ILogger<Worker> logger, IConfiguration configuration, Dictionary<string, dynamic?> configpar)
{
Configuration = configuration;
_ConfigPar = configpar;
_logger = logger;
Init();
}
...
In the method "Init()" relatively extensive tasks take place (on my PC it takes about 2 seconds). If these are through, it goes on here:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (int.TryParse(ConfigPar[cpQueryInterval], out int QueryInterval) == false)
{
QueryInterval = QueryIntervalStd;
Log.LogInformation(logInfo, $"Abfrageintervall konnte nicht ermittelt werden. Es wird daher der Standardwert von {QueryInterval} Millisekunden verwendet. Prüfen Sie die Angaben in der Parameterdatei.");
}
Log.LogInformation(logInfo, $"{Process.GetCurrentProcess().ProcessName} gestartet.");
Log.LogInformation(logInfo, $"Worker arbeitet mit Abfrageintervall von {QueryInterval} Millisekunden.");
while (stoppingToken.IsCancellationRequested == false)
{
await ProcessNewOrders();
await UpdateProducts();
Dhl_Polling();
await Task.Delay(QueryInterval, stoppingToken);
}
}
...
The service is supposed to fetch orders from an eShop every few minutes, update items and process DHL shipments.
Well, when I start the program manually in the command line (i.e. not as a service), everything works as expected. Now I have registered the program as a service and every time I try to start the service I get the following error: Error 1053: The service did not respond to the start or control request in a timely fashion
We started everything in Main:
private static async Task<int> Main(string[] args)
{
try
{
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = ServiceName;
})
.ConfigureServices(services =>
{
services.AddSingleton<Dictionary<string, dynamic?>> (_ConfigPar);
services.AddHostedService<Worker>();
})
.Build();
await host.RunAsync();
Log.LogInformation((LogInfo)_ConfigPar[cpLogInfo], $"{Process.GetCurrentProcess().ProcessName} beendet.");
if (Debugger.IsAttached == true)
{
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine($"{ex}{Environment.NewLine}{Environment.NewLine}");
...
How do I proceed to avoid this error?
Many thanks
René
|
|
|
|