یا اینکه میشود در حین آپلود توسط افزونه هم یک سری توضیحات اضافی رو ارسال کرد:
// JS up.settings.multipart_params = { description: $("#imageDescription").val() }; // C# string description = context.Request.Form["description"];
// JS up.settings.multipart_params = { description: $("#imageDescription").val() }; // C# string description = context.Request.Form["description"];
<div id="blazor-error-ui"> An unhandled error has occurred. <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div>
using System; using System.Net.Http; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace BlazorWasmTelegramLogger.Client.Logging { public class ClientLoggerProvider : ILoggerProvider { private readonly HttpClient _httpClient; private readonly WebApiLoggerOptions _options; private readonly NavigationManager _navigationManager; public ClientLoggerProvider( IServiceProvider serviceProvider, IOptions<WebApiLoggerOptions> options, NavigationManager navigationManager) { if (serviceProvider is null) { throw new ArgumentNullException(nameof(serviceProvider)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } _httpClient = serviceProvider.CreateScope().ServiceProvider.GetRequiredService<HttpClient>(); _options = options.Value; _navigationManager = navigationManager ?? throw new ArgumentNullException(nameof(navigationManager)); } public ILogger CreateLogger(string categoryName) { return new WebApiLogger(_httpClient, _options, _navigationManager); } public void Dispose() { } } }
using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace BlazorWasmTelegramLogger.Client.Logging { public static class ClientLoggerProviderExtensions { public static ILoggingBuilder AddWebApiLogger(this ILoggingBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } builder.Services.AddSingleton<ILoggerProvider, ClientLoggerProvider>(); return builder; } } }
public ClientLoggerProvider( IServiceProvider serviceProvider, IOptions<WebApiLoggerOptions> options, NavigationManager navigationManager)
public ILogger CreateLogger(string categoryName) { return new WebApiLogger(_httpClient, _options, _navigationManager); }
using System; using System.Net.Http; using System.Net.Http.Json; using BlazorWasmTelegramLogger.Shared; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Logging; namespace BlazorWasmTelegramLogger.Client.Logging { public class WebApiLogger : ILogger { private readonly WebApiLoggerOptions _options; private readonly HttpClient _httpClient; private readonly NavigationManager _navigationManager; public WebApiLogger(HttpClient httpClient, WebApiLoggerOptions options, NavigationManager navigationManager) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); _options = options ?? throw new ArgumentNullException(nameof(options)); _navigationManager = navigationManager ?? throw new ArgumentNullException(nameof(navigationManager)); } public IDisposable BeginScope<TState>(TState state) => default; public bool IsEnabled(LogLevel logLevel) => logLevel >= _options.LogLevel; public void Log<TState>( LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { if (!IsEnabled(logLevel)) { return; } if (formatter is null) { throw new ArgumentNullException(nameof(formatter)); } try { ClientLog log = new() { LogLevel = logLevel, EventId = eventId, Message = formatter(state, exception), Exception = exception?.Message, StackTrace = exception?.StackTrace, Url = _navigationManager.Uri }; _httpClient.PostAsJsonAsync(_options.LoggerEndpointUrl, log); } catch { // don't throw exceptions from the logger } } } }
using Microsoft.Extensions.Logging; namespace BlazorWasmTelegramLogger.Client.Logging { public class WebApiLoggerOptions { public string LoggerEndpointUrl { set; get; } public LogLevel LogLevel { get; set; } = LogLevel.Information; } }
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "WebApiLogger": { "LogLevel": "Warning", "LoggerEndpointUrl": "/api/logs" } }
namespace BlazorWasmTelegramLogger.Client { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.Services.Configure<WebApiLoggerOptions>(options => builder.Configuration.GetSection("WebApiLogger").Bind(options)); // … } } }
using Microsoft.Extensions.Logging; namespace BlazorWasmTelegramLogger.Shared { public class ClientLog { public LogLevel LogLevel { get; set; } public EventId EventId { get; set; } public string Message { get; set; } public string Exception { get; set; } public string StackTrace { get; set; } public string Url { get; set; } } }
namespace BlazorWasmTelegramLogger.Client { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.Configure<WebApiLoggerOptions>(options => builder.Configuration.GetSection("WebApiLogger").Bind(options)); builder.Services.AddLogging(configure => { configure.AddWebApiLogger(); }); await builder.Build().RunAsync(); } } }
public bool IsEnabled(LogLevel logLevel) => logLevel >= _options.LogLevel;
using System; using System.Text; using System.Threading.Tasks; using BlazorWasmTelegramLogger.Shared; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Telegram.Bot; using Telegram.Bot.Types.Enums; namespace BlazorWasmTelegramLogger.Server.Services { public class TelegramLoggingBotOptions { public string AccessToken { get; set; } public string ChatId { get; set; } } public interface ITelegramBotService { Task SendLogAsync(ClientLog log); } public class TelegramBotService : ITelegramBotService { private readonly string _chatId; private readonly TelegramBotClient _client; public TelegramBotService(IOptions<TelegramLoggingBotOptions> options) { _chatId = options.Value.ChatId; _client = new TelegramBotClient(options.Value.AccessToken); } public async Task SendLogAsync(ClientLog log) { var text = formatMessage(log); if (string.IsNullOrWhiteSpace(text)) { return; } await _client.SendTextMessageAsync(_chatId, text, ParseMode.Markdown); } private static string formatMessage(ClientLog log) { if (string.IsNullOrWhiteSpace(log.Message)) { return string.Empty; } var sb = new StringBuilder(); sb.Append(toEmoji(log.LogLevel)) .Append(" *") .AppendFormat("{0:hh:mm:ss}", DateTime.Now) .Append("* ") .AppendLine(log.Message); if (!string.IsNullOrWhiteSpace(log.Exception)) { sb.AppendLine() .Append('`') .AppendLine(log.Exception) .AppendLine(log.StackTrace) .AppendLine("`") .AppendLine(); } sb.Append("*Url:* ").AppendLine(log.Url); return sb.ToString(); } private static string toEmoji(LogLevel level) => level switch { LogLevel.Trace => "⬜️", LogLevel.Debug => "🟦", LogLevel.Information => "⬛️️️", LogLevel.Warning => "🟧", LogLevel.Error => "🟥", LogLevel.Critical => "❌", LogLevel.None => "🔳", _ => throw new ArgumentOutOfRangeException(nameof(level), level, null) }; } }
<Project Sdk="Microsoft.NET.Sdk.Web"> <ItemGroup> <PackageReference Include="Telegram.Bot" Version="15.7.1" /> </ItemGroup> </Project>
public class TelegramLoggingBotOptions { public string AccessToken { get; set; } public string ChatId { get; set; } }
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "TelegramLoggingBot": { "AccessToken": "1826…", "ChatId": "-1001…" } }
namespace BlazorWasmTelegramLogger.Server { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { services.Configure<TelegramLoggingBotOptions>(options => Configuration.GetSection("TelegramLoggingBot").Bind(options)); services.AddSingleton<ITelegramBotService, TelegramBotService>(); // ... } // ... } }
public class TelegramBotService : ITelegramBotService { private readonly string _chatId; private readonly TelegramBotClient _client; public TelegramBotService(IOptions<TelegramLoggingBotOptions> options) { _chatId = options.Value.ChatId; _client = new TelegramBotClient(options.Value.AccessToken); }
using System; using System.Threading.Tasks; using BlazorWasmTelegramLogger.Server.Services; using BlazorWasmTelegramLogger.Shared; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace BlazorWasmTelegramLogger.Server.Controllers { [ApiController] [Route("api/[controller]")] public class LogsController : ControllerBase { private readonly ILogger<LogsController> _logger; private readonly ITelegramBotService _telegramBotService; public LogsController(ILogger<LogsController> logger, ITelegramBotService telegramBotService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _telegramBotService = telegramBotService; } [HttpPost] public async Task<IActionResult> PostLog(ClientLog log) { // TODO: Save the client's `log` in the database _logger.Log(log.LogLevel, log.EventId, log.Url + Environment.NewLine + log.Message); await _telegramBotService.SendLogAsync(log); return Ok(); } } }
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; throw new InvalidOperationException("This is an exception message from the client!"); } }
when('/showOrderDetails/:orderId', { templateUrl: 'templates/show_order.html', controller: 'ShowOrderController' });
myFirstRoute .controller('ShowOrderController', function($scope, $routeParams) { $scope.order_id = $routeParams.orderId; });
<body ng-app="myFirstRoute" style=" <div> <div> <div> <table dir="rtl"> <thead> <tr> <th>#</th><th>˜کد</th><th>نام محصول</th><th></th> </tr> </thead> <tbody> <tr> <td>1</td><td>1234</td><td>15" Samsung Laptop</td> <td><a href="#showOrderDetails/1234">جزئیات محصول</a></td> </tr> <tr> <td>2</td><td>5412</td><td>2TB Seagate Hard drive</td> <td><a href="#showOrderDetails/5412">جزئیات محصول</a></td> </tr> <tr> <td>3</td><td>9874</td><td>D-link router</td> <td><a href="#showOrderDetails/9874">جزئیات محصول</a></td> </tr> </tbody> </table> <div ng-view></div> </div> </div> </div> <script src="js/bootstrap.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </body>
<h2>سفارش شماره #{{order_id}}</h2> محل قرار گیری جزئیات سفارش شماره : <b>#{{order_id}}</b>.
<script type="text/ng-template" id="add_order.html"> <h2> ثبت سفارش </h2> {{message}} </script>
when('/AddNewOrder', { templateUrl: 'add_order.html', controller: 'AddOrderController' }). when('/ShowOrders', { templateUrl: 'show_orders.html', controller: 'ShowOrdersController' });
myFirstRoute.controller('AddOrderController', function($scope) { $scope.message = 'صفحه نمایش ثبت سفارش جدید'; }); myFirstRoute.controller('ShowOrdersController', function($scope) { $scope.message = 'صفحه نمایش لیست سفارشات'; });
<body ng-app="myFirstRoute" style=" <div> <div> <div> <ul> <li><a href="#AddNewOrder"> ثبت سفارش جدید </a></li> <li><a href="#ShowOrders"> نمایش شفارشات </a></li> </ul> </div> <div> <div ng-view></div> </div> </div> </div> <script type="text/ng-template" id="add_order.html"> <h2> ثبت سفارش </h2> {{message}} </script> <script type="text/ng-template" id="show_orders.html"> <h2> نمایش سفارشات </h2> {{message}} </script> <script src="js/bootstrap.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </body>
when('/AddNewOrder', { templateUrl: 'templates/add_order.html', controller: 'CommonController', foodata: 'addorder' }). when('/ShowOrders', { templateUrl: 'templates/show_orders.html', controller: 'CommonController', foodata: 'showorders' }); sampleApp.controller('CommonController', function($scope, $route) { //access the foodata property using $route.current var foo = $route.current.foodata; alert(foo); });
$route.current.foodata
هنگامیکه خطاهای غیر منتظرهای در برنامهی مدیریت شدهی شما رخ میدهند، شما اطلاعات کمی را در مورد این مساله دارید. اگرچه شما میتوانید تا حدودی جلوی این نوع خطاهای غیرمنتظره را با ابزارهای خطایابی و یا لاگر، رصد کنید ولی همیشه اینطور نیست؛ در این حال ذخیره، تجزیه و تحلیل Dumpهای حافظه، ممکن است آخرین گزینه برای شما باشد. خوشبختانه ویژوال استودیو، ابزاری عالی برای تجزیه و تحلیل Dumpهای حافظه است! در این مطلب به شما نشان میدهیم که چگونه Dumpهای حافظه را جمع آوری کرده و توسط ویژوال استودیو راه حل مشکلات درج شدهی در آنها را پیدا کنید.
ابزارهایی وجود دارند که حافظه را مورد کاوش قرار داده و فعالیتهایی را که یک پروسس انجام میدهد، مانیتور میکنند. در حال حاضر ابزارهای مختلفی برای اینکار وجود دارند؛ از جمله Visual Studio ،ProcDump ،DebugDiag و WinDbg که ما در این پست از ProcDump استفاده میکنیم.
برای شروع، من یک برنامهی ساده را ایجاد کردم که شامل یک button است و با فشردن آن، یک خطای نامشخص اتفاق میافتد. برنامه را اجرا میکنیم. سپس به TaskManager رفته و آیدی پروسس برنامه را پیدا میکنیم:
آیدی پروسس ما، 10896 میباشد.
ProcDump را دانلود کرده و آنرا توسط CMD، به این صورت اجرا میکنیم تا تمامی فعالیتهای پروسس موردنظر را زیرنظر بگیرد و فایل Dump ای را تولید کند:
procdump.exe -ma -e 10896
حالا نوبت به کلیک بر روی Button، جهت ایجاد خطا میرسد. بر روی دکمه کلیک کرده و منتظر میشویم تا Dump، از حافظه جمع آوری و در سیستم تولید شود. عملیات با موفقیت انجام شده و فایل Dump در آدرس مشخص شده، ایجاد میشود.
بعد از ایجاد فایل Dump، نوبت به پیدا کردن منشا خطا و رسیدن به کد موردنظر میرسد. ویژوال استودیو را باز کنید و فایل Dump را درون VS درگ/دراپ کنید.
در پنجرهای که باز میشود، میتوانید مشخصات کاملی از برنامه را مشاهده کنید. سمت راست، چند گزینه وجود دارند که با توجه به نوع برنامه (مدیریت شده یا محلی) و زبان برنامه نویسی، باید آنها را انتخاب کنید. از آنجائیکه برنامهی ما با زبان سی شارپ ایجاد شده، گزینهی اول یعنی Debug with Managed only را انتخاب میکنیم.
بعد از انتخاب این گزینه، بلافاصله به کدی که باعث ایجاد خطا میشود، هدایت میشویم:
کلام آخر اینکه سعی کنید تا حد ممکن، خودتان خطاها را مدیریت کنید و از ابزارهای خطایاب مانند AppCenter نیز استفاده کنید. اخیرا WPF و WinForm نیز به AppCenter اضافه شدهاند.
PM> Install-Package jquery.mobile
<meta name="viewport" content="width=device-width">
<head> <meta name="viewport" content="width=device-width,initial-sclae=1" /> <link href="Content/jquery.mobile-1.1.0.css" rel="stylesheet" type="text/css" /> <script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script> <script src="Scripts/jquery.mobile-1.1.0.js" type="text/javascript"></script> <title></title> </head> <body> <div data-role="page"> <div data-role="header" data-theme="b"> <h1>this is a test </h1> </div> <div data-role="conent"> <ul data-role="listview" data-filter="true" data-inset="true" data-theme="e"> <li><a href="#">Water</a></li> <li><a href="#">Pepsi</a></li> <li><a href="#">Diet Pepsi</a></li> <li><a href="#">Beer</a></li> <a href="#" data-role="button" data-theme="b">Click ME</a> </ul> </div> <div data-role="footer" data-theme="b" data-position="fixed"> <h1>footer </h1> </div> </div> </body>
data-role="page"
" data-role="header
"data-theme="e
"data-role="listview
"data-filter="true
" data-inset="true"
این قابلیت عملا یک IDE مدرن (مشابه VSCode) توی Browser به همراه امکاناتی از جلمه (Intellisense و Run و Debug و Test و...) در اختیارتون میذاره. از این پس واسه توسعه کد ریپازیتوری هاتون میتونین بدون نیاز به Clone کردن، اون رو توی مروگر توسط این IDE توسعه بدین.
این قابلیت که هم اکنون به صورت beta منتشر شده، برای همگان دردسترس نیست و برای استفاده از آن باید درخواست Ealry Access ثبت کنید.
همچنین قابلیت جدید دیگری به نام GitHub Discussions معرفی شده که مشابه Forum یا Q&A بوده محلی برای گفتگو و پرسش و پاسخ حول مسائل فنی مخصوص یک ریپازیتوری هست (که تاکنون این گفتگوها معمولا توی Issueها و Pull Requestها به صورت پراکنده و غیر یکپارچه دیده میشد) و به نظر میرسه برای رسیدن به چیزی مشابه StackOverflow ایجاد شده
این قابلییت هم اکنون برای تعداد محدودی از ریپازیتوریها (مانند react-table) اعمال شده و برای همگان دردسترس نیست .
<package id="Microsoft.SqlServer.TransactSql.ScriptDom" version="12.0.1" targetFramework="net40" />