کار با اسکنر در برنامه های تحت وب (قسمت دوم و آخر)
نویسنده: محمد رعیت پیشه
تاریخ: ۱۳۹۳/۱۱/۲۰ ۲۳:۳۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
در قسمت قبل « کار با اسکنر در برنامههای تحت وب (قسمت اول) » دیدی از کاری که قرار است انجام دهیم، رسیدیم. حالا سراغ یک پروژهی عملی و پیاده سازی مطالب مطرح شده میرویم.
ابتدا پروژهی 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
}
} 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;
}
خروجی این متد همان عکس اسکن شده است که از نوع 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 استفاده میکنید، میتوانید از کدهای آن استفاده کنید.
private readonly Uri _baseAddress = new Uri("http://localhost:6019");
private ServiceHost _host; 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();
} <?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>
<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>
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
{ Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:13748/. This can be fixed by moving the resource to the same domain or enabling CORS.
catch(Exception ex)
{
Console.WriteLine(ex); System.Runtime.InteropServices.COMException (0x80210015): Exception from HRESULT: 0x80210015 at WIA.CommonDialogClass.ShowAcquireImage
finally
{
if(image!=null) Marshal.ReleaseComObject(image);
if(dialog!=null) Marshal.ReleaseComObject(dialog);
} Host is running. System.Runtime.InteropServices.COMException (0x80070050): The file exists. (Exception from HRESULT: 0x80070050) at WIA.ImageFileClass.SaveFile(String Filename) at SelfHost.ScannerService.GetScan() in g:\project\asnad\scan\SelfHostWcfScannerService\SelfHostWcfService\ScannerService.cs:line 25
_host = new ServiceHost(typeof(WcfServiceScanner.ScannerService), _baseAddress);
_host.Open(); _host.Close();
<script>
$( "#get-scan" ).click(function () {
var url = 'http://localhost:8010/' ;
$. get (url, function (data) {
$( "#img-scanned" ).attr( "src" , "data:image/Jpeg;base64, " + data.GetScanResult);
});
}); <httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol> <behaviorExtensions>
<add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>