releasing .NET Core 3.1.14 and .NET Core 2.1.27 April updates. These updates contains reliability and other non-security improvements.
اشتراکها
releasing .NET Core 3.1.14 and .NET Core 2.1.27 April updates. These updates contains reliability and other non-security improvements.
Change this section ... <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> </PropertyGroup> to the following ... <PropertyGroup> <TargetFramework>netcoreapp2.2</TargetFramework> <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel> <AspNetCoreModuleName>AspNetCoreModule</AspNetCoreModuleName> </PropertyGroup>
Following my last post on my ASP.NET MVC SEO-Framework I started looking at adding support also for ASP.NET Core MVC, with its superior Dependency Injection and Tag Helpers.
using System; namespace EFCoreDbFunctionsSample.Entities { public class Person { public int Id { get; set; } public string Name { get; set; } public DateTime AddDate { get; set; } } }
var usersInfo = context.People.Where(person => (DateTime.Now - person.AddDate).Days <= 10).ToList();
'The LINQ expression 'DbSet<Person>.Where(p => (DateTime.Now - p.AddDate).Days <= 10)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
SELECT [p].[Id], [p].[AddDate], [p].[Name] FROM [People] AS [p] WHERE DATEDIFF(Day, [p].[AddDate], GETDATE()) <= 10
namespace EFCoreDbFunctionsSample.DataLayer { public enum SqlDateDiff { Year, Quarter, Month, DayOfYear, Day, Week, Hour, Minute, Second, MilliSecond, MicroSecond, NanoSecond } public static class SqlDbFunctionsExtensions { public static int SqlDateDiff(SqlDateDiff interval, DateTime initial, DateTime end) => throw new InvalidOperationException($"{nameof(SqlDateDiff)} method cannot be called from the client side."); public static readonly MethodInfo SqlDateDiffMethodInfo = typeof(SqlDbFunctionsExtensions) .GetRuntimeMethod( nameof(SqlDbFunctionsExtensions.SqlDateDiff), new[] { typeof(SqlDateDiff), typeof(DateTime), typeof(DateTime) } ); } }
namespace EFCoreDbFunctionsSample.DataLayer { public class ApplicationDbContext : DbContext { // ... protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.HasDbFunction(SqlDbFunctionsExtensions.SqlDateDiffMethodInfo) .HasTranslation(args => { var parameters = args.ToArray(); var param0 = ((SqlConstantExpression)parameters[0]).Value.ToString(); return SqlFunctionExpression.Create("DATEDIFF", new[] { new SqlFragmentExpression(param0), // It should be written as DateDiff(day, ...) and not DateDiff(N'day', ...) . parameters[1], parameters[2] }, SqlDbFunctionsExtensions.SqlDateDiffMethodInfo.ReturnType, typeMapping: null); }); } } }
var sinceDays = 10; users = context.People.Where(person => SqlDbFunctionsExtensions.SqlDateDiff(SqlDateDiff.Day, person.AddDate, DateTime.Now) <= sinceDays).ToList(); /* SELECT [p].[Id], [p].[AddDate], [p].[Name] FROM [People] AS [p] WHERE DATEDIFF(Day, [p].[AddDate], GETDATE()) <= @__sinceDays_0 */
.NET Core SDK | .NET Core Runtime | Compatible Visual Studio | MSBuild | Notes |
---|---|---|---|---|
2.1.5nn | 2.1 | 2017 | 15 | Installed as part of VS 2017 version 15.9 |
2.1.6nn | 2.1 | 2019 | 16 | Installed as part of VS 2019 |
2.2.1nn | 2.2 | 2017 | 15 | Installed manually |
2.2.2nn | 2.2 | 2019 | 16 | Installed as part of VS 2019 |
3.0.1nn | 3.0 (Preview) | 2019 | 16 | Installed manually |
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> </PropertyGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <LangVersion>preview</LangVersion> </PropertyGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <LangVersion>8.0</LangVersion> </PropertyGroup> </Project>
> dotnet --list-sdks
> dotnet new globaljson --sdk-version 2.2.300 > type global.json
using(var client = new HttpClient()) { // do something with http client }
Unable to connect to the remote server System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
using (var client = new HttpClient()) { var result = await client.GetAsync("http://example.com/"); }
for (int i = 0; i < 10; i++) { using (var client = new HttpClient()) { var result = await client.GetAsync("http://example.com/"); Console.WriteLine(result.StatusCode); } }
TCP 192.168.1.6:13996 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:13997 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:13998 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:13999 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:14000 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:14001 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:14002 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:14003 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:14004 93.184.216.34:http TIME_WAIT TCP 192.168.1.6:14005 93.184.216.34:http TIME_WAIT
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]
CancelPendingRequests DeleteAsync GetAsync GetByteArrayAsync GetStreamAsync GetStringAsync PostAsync PutAsync SendAsync
BaseAddress DefaultRequestHeaders MaxResponseContentBufferSize Timeout
var sp = ServicePointManager.FindServicePoint(new Uri("http://thisisasample.com")); sp.ConnectionLeaseTimeout = 60*1000; //In milliseconds
using System; using System.Collections.Generic; using System.Net.Http; namespace HttpClientTips { public interface IHttpClientFactory : IDisposable { HttpClient GetOrCreate( Uri baseAddress, IDictionary<string, string> defaultRequestHeaders = null, TimeSpan? timeout = null, long? maxResponseContentBufferSize = null, HttpMessageHandler handler = null); } }
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading; namespace HttpClientTips { /// <summary> /// Lifetime of this class should be set to `Singleton`. /// </summary> public class HttpClientFactory : IHttpClientFactory { // 'GetOrAdd' call on the dictionary is not thread safe and we might end up creating the HttpClient more than // once. To prevent this Lazy<> is used. In the worst case multiple Lazy<> objects are created for multiple // threads but only one of the objects succeeds in creating the HttpClient. private readonly ConcurrentDictionary<Uri, Lazy<HttpClient>> _httpClients = new ConcurrentDictionary<Uri, Lazy<HttpClient>>(); private const int ConnectionLeaseTimeout = 60 * 1000; // 1 minute public HttpClientFactory() { // Default is 2 minutes: https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.dnsrefreshtimeout(v=vs.110).aspx ServicePointManager.DnsRefreshTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds; // Increases the concurrent outbound connections ServicePointManager.DefaultConnectionLimit = 1024; } public HttpClient GetOrCreate( Uri baseAddress, IDictionary<string, string> defaultRequestHeaders = null, TimeSpan? timeout = null, long? maxResponseContentBufferSize = null, HttpMessageHandler handler = null) { return _httpClients.GetOrAdd(baseAddress, uri => new Lazy<HttpClient>(() => { // Reusing a single HttpClient instance across a multi-threaded application means // you can't change the values of the stateful properties (which are not thread safe), // like BaseAddress, DefaultRequestHeaders, MaxResponseContentBufferSize and Timeout. // So you can only use them if they are constant across your application and need their own instance if being varied. var client = handler == null ? new HttpClient { BaseAddress = baseAddress } : new HttpClient(handler, disposeHandler: false) { BaseAddress = baseAddress }; setRequestTimeout(timeout, client); setMaxResponseBufferSize(maxResponseContentBufferSize, client); setDefaultHeaders(defaultRequestHeaders, client); setConnectionLeaseTimeout(baseAddress, client); return client; }, LazyThreadSafetyMode.ExecutionAndPublication)).Value; } public void Dispose() { foreach (var httpClient in _httpClients.Values) { httpClient.Value.Dispose(); } } private static void setConnectionLeaseTimeout(Uri baseAddress, HttpClient client) { // This ensures connections are used efficiently but not indefinitely. client.DefaultRequestHeaders.ConnectionClose = false; // keeps the connection open -> more efficient use of the client ServicePointManager.FindServicePoint(baseAddress).ConnectionLeaseTimeout = ConnectionLeaseTimeout; // ensures connections are not used indefinitely. } private static void setDefaultHeaders(IDictionary<string, string> defaultRequestHeaders, HttpClient client) { if (defaultRequestHeaders == null) { return; } foreach (var item in defaultRequestHeaders) { client.DefaultRequestHeaders.Add(item.Key, item.Value); } } private static void setMaxResponseBufferSize(long? maxResponseContentBufferSize, HttpClient client) { if (maxResponseContentBufferSize.HasValue) { client.MaxResponseContentBufferSize = maxResponseContentBufferSize.Value; } } private static void setRequestTimeout(TimeSpan? timeout, HttpClient client) { if (timeout.HasValue) { client.Timeout = timeout.Value; } } } }
namespace HttpClientTips.Web { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IHttpClientFactory, HttpClientFactory>(); services.AddMvc(); }
namespace HttpClientTips.Web.Controllers { public class HomeController : Controller { private readonly IHttpClientFactory _httpClientFactory; public HomeController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task<IActionResult> Index() { var host = new Uri("http://localhost:5000"); var httpClient = _httpClientFactory.GetOrCreate(host); var responseMessage = await httpClient.GetAsync("home/about").ConfigureAwait(false); var responseContent = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); return Content(responseContent); }