The new async
and await
keywords—which make
asynchronous code more concise, obvious, and maintainable—have arrived
in Firefox 52. Currently available in the latest Developer Edition release, Firefox 52 is scheduled for general release in March 2017.
ابتدا باید فضای نام System.Web.Routing را در فایل Global.asax اضافه کنیم .
protected void Application_Start(object sender, EventArgs e) { RouteTable.Routes.MapPageRoute("Product", "Product/{Name}", "~/Product.aspx"); }
RouteTable.Routes.MapPageRoute("PostDetail", "Post/{pi}/{pt}", "~/PostShow.aspx");
<a href='<%# string.Format("/Post/{0}/{1}",Eval("PostID"),Eval("PostTitle").ToString().Replace(" ","-")) %>'>
Post/12/چگونه-طراحان-وب-به-جهنم-می-روند!؟
int pi = int.Parse(Page.RouteData.Values["pi"].ToString()); Posts post = (from p in con.Posts where p.PostID == pi select p).FirstOrDefault();
<asp:EntityDataSource ID="EntityDataSource1" runat="server" AutoGenerateWhereClause="True" ConnectionString="name=WebWorkEntities" DefaultContainerName="WebWorkEntities" EnableFlattening="False" EntitySetName="Posts" EntityTypeFilter="Posts" Where="" Select=""> <WhereParameters> <asp:RouteParameter Name="PostID" RouteKey="pi" DbType="Int32" DefaultValue="0" /> </WhereParameters> </asp:EntityDataSource>
protected void Application_Start(object sender, EventArgs e) { RoutingSite(RouteTable.Routes); } public static void RoutingSite(RouteCollection route) { route.MapPageRoute("PostDetail", "Post/{pi}/{pt}", "~/PostShow.aspx"); route.MapPageRoute("RouteAbout", "About-Me", "~/About.aspx"); }
window.onbeforeunload = function (e) { $.connection.hub.stop(); };
فرم ساز JQuery
انقضای اهراز هویت کاربر پس از رفرش کردن صفحه در پروژه ای مشابه
برای یادگیری من دارم پروژه ای شبیه به پروژه شما میسازم. یعنی به عبارتی مراحل شمارو یکی ، یکی طی میکنم. حالا به جایی رسیدم که هرچقدر هم تلاش کردم متاسفانه پاسخی براش پیدا نکردم.
مشکل من اینه. زمانی که کاربر دکمه ورود رو میزنه و وارد سیستم میشه ، زمانی که صفحه رو رفرش کنه یا از صفحه ای به صفحهی دیگه بره اهراز هویتیش تموم میشه. با اینکه "مرا به خاطر داشته باش" رو هم تیک میزنم ولی باز این مشکل پیش میاد. جالب اینجاست کدهای خودتون به درستی در پروژه خودتون کار میکنه ولی وقتی میارمشون تو پروژهی خودم این مشکل پیش میاد. نمیدونم کجارو اشتباه کردم ولی میدونم یک چیزی کمه.
توجه کنید زمانی که کاربر ورود میکنه مقدار @User.Identity.IsAuthenticated برابر با true هستش. پس قطعا کاربر ورود میکنه ولی زمانی که صفحه تغییر میکنه این مقدار برابر false میشه.
کدهای کلاس Startup دقیقا همون کدهای شما و من تغییری بهشون ندادم فقط اسم کوکی رو عوض کردم یعنی اینطوری :
public class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); app.MapSignalR(); } private static void ConfigureAuth(IAppBuilder appBuilder) { const int twoWeeks = 14; ProjectObjectFactory.Container.Configure(config => config.For<IDataProtectionProvider>() .HybridHttpOrThreadLocalScoped() .Use(() => appBuilder.GetDataProtectionProvider())); appBuilder.CreatePerOwinContext( () => ProjectObjectFactory.Container.GetInstance<ApplicationUserManager>()); appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), ExpireTimeSpan = TimeSpan.FromDays(twoWeeks), SlidingExpiration = true, CookieName = "MyFirstCms", Provider = new CookieAuthenticationProvider { OnValidateIdentity = ProjectObjectFactory.Container.GetInstance<IApplicationUserManager>().OnValidateIdentity() } }); ProjectObjectFactory.Container.GetInstance<IApplicationRoleManager>() .SeedDatabase(); ProjectObjectFactory.Container.GetInstance<IApplicationUserManager>() .SeedDatabase(); appBuilder.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. //appBuilder.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); // Enables the application to remember the second login verification factor such as phone or email. // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. // This is similar to the RememberMe option when you log in. // appBuilder.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); appBuilder.UseFacebookAuthentication( appId: "fdsfdsfs", appSecret: "fdfsfs"); appBuilder.UseGoogleAuthentication( clientId: "fdsfsdfs", clientSecret: "fdsfsf"); } }
این هم کدهای صفحه ورود :
[HttpPost] [AllowAnonymous] //[CheckReferrer] [ValidateAntiForgeryToken] public virtual async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } if (!_userManager.CheckUserNameExist(model.UserName,null)) { this.AddErrors("UserName", "نام کاربری یا کلمه عبور وارد شده نادرست است"); return View(model); } if (_userManager.CheckIsUserBannedOrDelete(model.UserName)) { this.AddErrors("UserName", "حساب کاربری شما مسدود شده است"); return View(model); } if (!_userManager.IsEmailConfirmedByUserNameAsync(model.UserName)) { this.NotyWarning("برای ورود به سایت لازم است حساب خود را فعال کنید"); return RedirectToAction(MVC.Account.ActionNames.ReceiveActivatorEmail, MVC.Account.Name); } var result = await _signInManager.PasswordSignInAsync (model.UserName.ToLower(), model.Password, model.RememberMe, shouldLockout: true); switch (result) { case SignInStatus.Success: this.NotySuccess("شما با موفقیت وارد سیستم شدید"); return RedirectToLocal(returnUrl); case SignInStatus.LockedOut: this.NotyError( $"دقیقه دوباره امتحان کنید {_userManager.DefaultAccountLockoutTimeSpan} حساب شما قفل شد ! لطفا بعد از "); return View(model); case SignInStatus.Failure: this.NotyError(ModelState.GetListOfErrors()); return View(model); default: this.NotyError( "در این لحظه امکان ورود به سابت وجود ندارد . مراتب را با مسئولان سایت در میان بگذارید"); return View(model); } }
ممنون میشم اگر میدونید کجارو اشتباه کردم بهم بگید.
با سپاس
ابتدا میخواهیم یک الگو یا Template را درست کنیم و بعدها از روی آن، نامهی جدیدی
را ایجاد کنیم و فیلدهایش را پرکنیم. برای اینکار یک سند جدید را در Word
ایجاد و به سربرگ Mailings مراجعه میکنیم. سپس دکمهی Select Recipients
را بزنید. در ادامه از منوی باز شده، Type a NewList را بزنید. با اینکار پنجرهای باز
میشود. در اینجا دکمهی Customize Columns را بزنید. این پنجره شامل فیلدهایی میشود که
میتوانید از آن استفاده کنید و بر روی سند قرار دهید و داخل برنامه با پیدا کردن
این فیلدها میتوانید بجای آنها، مقدار مورد نظرتان را پاس دهید. حالا شما نیاز
دارید تا از طریق دکمهی Add، تمامی فیلدهای لازم یک نامه را بسازید. پس از این کار، در هر دو پنجره ،
دکمهی OK را بزنید. بدین صورت یک پنجرهی ذخیره برای شما باز میشود تا این فیلدهایی را
که ایجاد کردید، به عنوان یک دیتابیس کوچک ذخیره شود که تمامی فیلدها را
دارا میباشد و هر موقع که خواستید دوباره میتوانید از همین فیلدها استفاده
کنید.
حالا میرسیم به قرار دادن این فیلدها داخل سند. با ذخیره
کردن فیلدها، تمامی گزینههای سربرگ Mailings فعال میشود. شما برای اینکه
فیلدی را بر روی سند قرار دهید، روی Insert Merge Field کلیک و متناسب با نیازتان،
فیلدها را قرار دهید و الگو را طراحی کنید. یک نمونه:
حالا فایل را با پسوند DOT. ذخیره کنید. در ادامه این فایل را در دیتابیس، به این روش ذخیره کنید:
String FilePath = "Template Path" // Converting File to ByteArray byte[] FileBuffer = System.IO.File.ReadAllBytes(FilePath); // Now you can insert this file buffer to DB
الان، الگوی ما آمادهاست و میتوانیم از طریق برنامه، به این الگو دسترسی داشته باشیم و به آن پارامتر ارسال کنیم.
روش ارسال پارامترها به الگوهای Word
حالا
فرضا شما یک فرم دارید که از کاربر، اطلاعاتی را دریافت میکند و میخواهید همین
اطلاعات را به Word ارسال کنید. برای اینکار ابتدا باید
یک نمونه از الگویی را که طراحی کردهایم، داخل سیستم ذخیره کنیم. یعنی باید آنرا از
دیتابیس فراخوانی کنیم و آن آرایهی بایتی را، بر روی سیستم، تبدیل به فایل
کنیم. سپس از سمت برنامه، تمامی فیلدهای موجود در این الگو را خوانده و بجای تک تک آنها، مقدار مناسبی را قرار دهیم. در نهایت این فایل را توسط کدنویسی بر
روی سیستم کاربر ذخیره میکنیم. فایل را تبدیل به آرایه بایتی میکنیم، داخل
دیتابیس درج میکنیم و فایل را از سیستم کاربر حذف میکنیم.
بنابراین در ادامه ابتدا
Assembly مربوط به MicroSoft.Office.Interop.Word را به رفرنسهای پروژه اضافه
میکنیم و سربرگش را هم Using میکنیم.
حالا میرسیم به کد نویسی:
کدهای زیر را به صورت سراسری داخل فرم تعریف میکنیم:
//LOCATION OF THE TEMPLATE FILE ON THE MACHINE; Object oTemplatePath = string.Format("{0}\\NewDocument.dot", Application.StartupPath); //OBJECT OF MISSING "NULL VALUE" Object oMissing = System.Reflection.Missing.Value; //OBJECTS OF FALSE AND TRUE Object oTrue = true; Object oFalse = false; //CREATING OBJECTS OF WORD AND DOCUMENT Microsoft.Office.Interop.Word.Application oWord = null; Microsoft.Office.Interop.Word.Document oWordDoc = null;
// Fetching Template ByteArray From Database => Byte[] YourTemplateByteArray = Fetch Template; System.IO.File.WriteAllBytes(oTemplatePath.ToString(), YourByteArray); oWord = new Microsoft.Office.Interop.Word.Application(); oWordDoc = new Microsoft.Office.Interop.Word.Document(); //Adding A New Document From A Template oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing); int iTotalFields = 0; // Finding Mailmerge Fields foreach(Microsoft.Office.Interop.Word.Field myMergeField in oWordDoc.Fields) { iTotalFields++; Microsoft.Office.Interop.Word.Range rngFieldCode = myMergeField.Code; String fieldText = rngFieldCode.Text; // Only Get The Mailmerge Fields if (fieldText.StartsWith(" MERGEFIELD")) { // Gives The Fieldnames as Entered in .DOT File string fieldName = fieldText.Substring(12, fieldText.IndexOf(" ", 12) - 12); switch (fieldName) { case "Letter_No": myMergeField.Select(); oWord.Selection.TypeText(txtLetterNo.Text); break; case "Letter_Date": myMergeField.Select(); oWord.Selection.TypeText(DateTime.Now); break; case "Letter_Has_Attachment": myMergeField.Select(); oWord.Selection.TypeText("دارد یا ندارد"); break; // And So On default: break; } } } //Showing The Document To The User oWord.Visible = true;
در ادامه یک دکمه را برای ذخیرهی فایل ورد قرار میدهیم. زمانیکه کاربر تایپ کردنش تمام شد و هنوز برنامهی ورد در حال اجراست، این دکمه را اجرا میکند. دقت کنید برنامهی ورد نباید بسته شود؛ باید باز باشد. بعد دکمهی ذخیره را میزنیم. با کدنویسی، برنامهی Word را خودمان میبندیم؛ نیازی به دخالت کاربر نیست.
oWordDoc.Save(); //Closing the file oWordDoc.Close(ref oFalse, ref oMissing, ref oMissing); //Quitting the application oWord.Quit(ref oMissing, ref oMissing, ref oMissing); byte[] FileBuffer = System.IO.File.ReadAllBytes(oTemplatePath.ToString ()); // Now Insert The FileBuffer Into Database as A Letter
خوب؛ کار تمام است! حالا فیلد FileBuffer را باید بسته به کدنویسی خودتان، داخل دیتابیس ذخیره کنید که برای بعدها بتوانید آنرا واکشی کرده و به کاربر نمایش دهید. این هم نمونهی نهایی جایگذاری فیلدها:
این آموزش را خیلی سال پیش در این تاپیک داخل فوروم برنامه نویس نوشته بودم.
در قسمت قبل « کار با اسکنر در برنامههای تحت وب (قسمت اول) » دیدی از کاری که قرار است انجام دهیم، رسیدیم. حالا سراغ یک پروژهی عملی و پیاده سازی مطالب مطرح شده میرویم.
ابتدا پروژهی WCF را شروع میکنیم. ویژوال استودیو را باز کرده و از قسمت New Project > Visual C# > WCF یک پروژهی WCF Service Application جدید را مثلا با نام "WcfServiceScanner" ایجاد نمایید. پس از ایجاد، دو فایل IService1.cs و Service1.scv موجود را به IScannerService و ScannerService تغییر نام دهید. سپس ابتدا محتویات کلاس اینترفیس IScannerService را به صورت زیر تعریف نمایید :
[ServiceContract] public interface IScannerService { [OperationContract] [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetScan")] string GetScan(); }
public class ScannerService : IScannerService { public string GetScan() { // TODO Add code here } }
بر روی پروژهی خود راست کلیک کرده و Add Reference را انتخاب نموده و سپس در قسمت COM، گزینهی Microsoft Windows Image Acquisition Library v2.0 را به پروژهی خود اضافه نمایید.
با اضافه شدن این ارجاع به پروژه، دسترسی به فضای نام WIA برای ما امکان پذیر میشود که ارجاعی از آن را در کلاس ScannerService قرار میدهیم.
using WIA;
public string GetScan() { var imgResult = String.Empty; var dialog = new CommonDialogClass(); try { // نمایش فرم پیشفرض اسکنر var image = dialog.ShowAcquireImage(WiaDeviceType.ScannerDeviceType); // ذخیره تصویر در یک فایل موقت var filename = Path.GetTempFileName(); image.SaveFile(filename); var img = Image.FromFile(filename); // img جهت ارسال سمت کاربر و نمایش در تگ Base64 تبدیل تصویر به imgResult = ImageHelper.ImageToBase64(img, ImageFormat.Jpeg); } catch { // از آنجاییه که امکان نمایش خطا وجود ندارد در صورت بروز خطا رشته خالی // بازگردانده میشود که به معنای نبود تصویر میباشد } return imgResult; }
CommonDialogClass کلاس اصلی در اینجا جهت نمایش فرم کار با اسکنر میباشد و متدهای مختلفی را جهت ارتباط با اسکنر در اختیار ما قرار میدهد که بسته به نیاز خود میتوانید از آنها استفاده کنید. برای نمونه در مثال ما نیز متد اصلی که مورد استفاده قرار گرفته، ShowAcquireImage میباشد که این متد، فرم پیش فرض دریافت اسکنر را به کاربر نمایش میدهد و کاربر از طریق آن میتواند قبل از شروع اسکن، یکسری تنظیمات را انجام دهد.
این متد ابتدا به صورت خودکار فرم تعیین دستگاه اسکنر ورودی را نمایش داده :
و سپس فرم پیش فرض اسکنرهای TWAIN را جهت تعیین تنظیمات اسکن نمایش میدهد که این امکان نیز در این فرم فراهم است تا دستگاههای Feeder یا Flated انتخاب گردند.
خروجی این متد همان عکس اسکن شده است که از نوع WIA.ImageFile میباشد و ما پس از دریافتش، ابتدا آن را در یک فایل موقت ذخیره نموده و سپس با استفاده از یک متد کمکی آن را به فرمت Base64 برای درخواست کننده اسکن ارسال مینماییم.
کدهای کلاس کمکی ImageHelper:
public static string ImageToBase64(Image image, System.Drawing.Imaging.ImageFormat format) { if (image != null) { using (MemoryStream ms = new MemoryStream()) { // Convert Image to byte[] image.Save(ms, format); byte[] imageBytes = ms.ToArray(); // Convert byte[] to Base64 String string base64String = Convert.ToBase64String(imageBytes); return base64String; } } return String.Empty; }
این مثال به سادهترین شکل نوشته شد. کلاس دیگری هم در اینجا وجود دارد و در صورتیکه از اسکنر نوع Feeder استفاده میکنید، میتوانید از کدهای آن استفاده کنید.
جهت رفع این خطا، در قسمت Referenceهای پروژه خود، WIA را انتخاب نموده و از Propertiesهای آن خصوصیت Embed Interop Types را به False تغییر دهید؛ مشکل حل میشود.
به سراغ پروژهی ویندوز فرم جهت هاست کردن این WCF سرویس میرویم. میتوانید این سرویس را بر روی یک Console App یا Windows Service هم هاست کنید که در اینجا برای سادگی مثال، از WinForm استفاده میکنیم.
یک پروژهی WinForm جدید را ایجاد کنید و سپس از قسمت Add Reference > Solution به مسیر پروژهی قبلی رفته و dllهای آن را به پروژه خود اضافه نمایید.
Form1.cs را باز کرده و ابتدا دو متغیر زیر را در آن به صورت عمومی تعریف نمایید:
private readonly Uri _baseAddress = new Uri("http://localhost:6019"); private ServiceHost _host;
حال در رویداد Form_Load برنامه، کدهای زیر را جهت هاست کردن سرویس اضافه مینماییم:
private void Form1_Load(object sender, EventArgs e) { _host = new ServiceHost(typeof(WcfServiceScanner.ScannerService), _baseAddress); _host.Open(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { _host.Close(); }
فایل App.Config پروژهی WinForm را باز کرده و کدهای آنرا مطابق زیر تغییر دهید:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="BehaviourMetaData"> <serviceMetadata httpGetEnabled="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="WcfServiceScanner.ScannerService" behaviorConfiguration="BehaviourMetaData"> <endpoint address="" binding="basicHttpBinding" contract="WcfServiceScanner.IScannerService" /> </service> </services> </system.serviceModel> </configuration>
اگر موفق به اجرا نشدید و احیانا با خطای زیر مواجه شدید، اطمینان حاصل کنید که ویژوال استودیو Run as Administrator باشد. مشکل حل خواهد شد.
به سراغ پروژهی بعدی، یعنی وب سایت خود میرویم. یک پروژهی MVC جدید ایجاد نمایید و در View مورد نظر خود، کدهای زیر را جهت صدا زدن متد GetScan اضافه میکنیم.
( از آنجا که کدها به صورت جاوا اسکریپت میباشد، پس مهم نیست که حتما پروژه MVC باشد؛ یک صفحهی HTML ساده هم کافی است).
<a href="#" id="get-scan">Get Scan</a> <img src="" id="img-scanned" /> <script> $("#get-scan").click(function () { var url = 'http://localhost:6019/'; $.get(url, function (data) { $("#img-scanned").attr("src","data:image/Jpeg;base64, "+ data.GetScanResult); }); }); </script>
راه حلهای زیادی برای این مشکل ارائه شده است، و متاسفانه بسیاری از آنها در شرایط پروژهی ما جوابگو نمیباشد (به دلیل هاست روی یک پروژه ویندوزی). تنها راه حل مطمئن (تست شده) استفاده از یک کلاس سفارشی در پروژهی WCF Service میباشد که مثال آن در اینجا آورده شده است.
برای رفع مشکل به پروژه WcfServiceScanner بازگشته و کلاس جدیدی را به نام CORSSupport ایجاد کرده و کدهای زیر را به آن اضافه کنید:
public class CORSSupport : IDispatchMessageInspector { Dictionary<string, string> requiredHeaders; public CORSSupport(Dictionary<string, string> headers) { requiredHeaders = headers ?? new Dictionary<string, string>(); } public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext) { var httpRequest = request.Properties["httpRequest"] as HttpRequestMessageProperty; if (httpRequest.Method.ToLower() == "options") instanceContext.Abort(); return httpRequest; } public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { var httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty; var httpRequest = correlationState as HttpRequestMessageProperty; foreach (var item in requiredHeaders) { httpResponse.Headers.Add(item.Key, item.Value); } var origin = httpRequest.Headers["origin"]; if (origin != null) httpResponse.Headers.Add("Access-Control-Allow-Origin", origin); var method = httpRequest.Method; if (method.ToLower() == "options") httpResponse.StatusCode = System.Net.HttpStatusCode.NoContent; } } // Simply apply this attribute to a DataService-derived class to get // CORS support in that service [AttributeUsage(AttributeTargets.Class)] public class CORSSupportBehaviorAttribute : Attribute, IServiceBehavior { #region IServiceBehavior Members void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { var requiredHeaders = new Dictionary<string, string>(); //Chrome doesn't accept wildcards when authorization flag is true //requiredHeaders.Add("Access-Control-Allow-Origin", "*"); requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS"); requiredHeaders.Add("Access-Control-Allow-Headers", "Accept, Origin, Authorization, X-Requested-With,Content-Type"); requiredHeaders.Add("Access-Control-Allow-Credentials", "true"); foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers) { foreach (EndpointDispatcher ed in cd.Endpoints) { ed.DispatchRuntime.MessageInspectors.Add(new CORSSupport(requiredHeaders)); } } } void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } #endregion }
using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher;
[CORSSupportBehavior] public class ScannerService : IScannerService {
کار تمام است، یکبار دیگر ابتدا پروژهی WcfServiecScanner و سپس پروژه هاست را Build کرده و برنامهی هاست را اجرا کنید. اکنون مشاهده میکنید که با زدن دکمهی اسکن، اسکنر فرم تنظیمات اسکن را نمایش میدهد که پس از زدن دکمهی Scan، پروسه آغاز شده و پس از اتمام، تصویر اسکن شده در صفحهی وب سایت نمایش داده میشود.