11 changed files with 669 additions and 23 deletions
@ -0,0 +1,16 @@ |
|||
<Window x:Class="BBWY.Client.Views.Order.GrabJDMibole" |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
xmlns:local="clr-namespace:BBWY.Client.Views.Order" |
|||
mc:Ignorable="d" |
|||
WindowStartupLocation="CenterScreen" |
|||
Title="GrabJDMibole" Height="350" Width="400"> |
|||
<Grid x:Name="grid"> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition/> |
|||
<RowDefinition Height="30"/> |
|||
</Grid.RowDefinitions> |
|||
</Grid> |
|||
</Window> |
@ -0,0 +1,98 @@ |
|||
using Microsoft.Web.WebView2.Core; |
|||
using Microsoft.Web.WebView2.Wpf; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Data; |
|||
using System.Windows.Documents; |
|||
using System.Windows.Input; |
|||
using System.Windows.Media; |
|||
using System.Windows.Media.Imaging; |
|||
using System.Windows.Shapes; |
|||
using io = System.IO; |
|||
|
|||
namespace BBWY.Client.Views.Order |
|||
{ |
|||
/// <summary>
|
|||
/// GrabJDMibole.xaml 的交互逻辑
|
|||
/// </summary>
|
|||
public partial class GrabJDMibole : Window |
|||
{ |
|||
private WebView2 wb2; |
|||
//private Stopwatch sw;
|
|||
private string orderId; |
|||
|
|||
public GrabJDMibole(string orderId) |
|||
{ |
|||
InitializeComponent(); |
|||
this.orderId = orderId; |
|||
this.Loaded += GrabJDMibole_Loaded; |
|||
this.Unloaded += GrabJDMibole_Unloaded; |
|||
} |
|||
|
|||
private void GrabJDMibole_Unloaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
this.Unloaded -= GrabJDMibole_Unloaded; |
|||
if (wb2 != null && wb2.CoreWebView2 != null) |
|||
{ |
|||
wb2.CoreWebView2InitializationCompleted -= Wb2_CoreWebView2InitializationCompleted; |
|||
wb2.NavigationCompleted -= Wb2_NavigationCompleted; |
|||
wb2.WebMessageReceived -= CoreWebView2_WebMessageReceived; |
|||
//wb2.Dispose();
|
|||
Console.WriteLine("wb2 Disposed"); |
|||
} |
|||
} |
|||
|
|||
private void GrabJDMibole_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
//sw = new Stopwatch();
|
|||
wb2 = new WebView2(); |
|||
grid.Children.Add(wb2); |
|||
//sw.Start();
|
|||
var wb2Setting = CoreWebView2Environment.CreateAsync(userDataFolder: io.Path.Combine(io.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "WebView2UserData")).Result; |
|||
wb2.EnsureCoreWebView2Async(wb2Setting); |
|||
wb2.CoreWebView2InitializationCompleted += Wb2_CoreWebView2InitializationCompleted; |
|||
wb2.NavigationCompleted += Wb2_NavigationCompleted; |
|||
wb2.WebMessageReceived += CoreWebView2_WebMessageReceived; |
|||
} |
|||
private void Wb2_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e) |
|||
{ |
|||
//sw.Stop();
|
|||
//Console.WriteLine(sw.ElapsedMilliseconds);
|
|||
wb2.CoreWebView2.Navigate($"https://neworder.shop.jd.com/order/orderDetail?orderId={orderId}"); |
|||
} |
|||
|
|||
private async void Wb2_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) |
|||
{ |
|||
//Console.WriteLine(wb2.CoreWebView2.Source);
|
|||
//Console.WriteLine(wb2.Source);
|
|||
if (wb2.CoreWebView2.Source.StartsWith("https://passport.shop.jd.com/login")) |
|||
{ |
|||
//首次打开需要登录
|
|||
await wb2.CoreWebView2.ExecuteScriptAsync("window.scrollTo(790,150)"); |
|||
await wb2.CoreWebView2.ExecuteScriptAsync("document.querySelector(\"div[data-tab-id='form']\").click()"); |
|||
} |
|||
else if (wb2.CoreWebView2.Source.StartsWith("https://neworder.shop.jd.com/order/orderDetail")) |
|||
{ |
|||
//进入订单详情页面,触发点击查看手机号
|
|||
Console.WriteLine("触发查看手机号"); |
|||
var js = @"var mobileNode = document.getElementById('mobile');
|
|||
mobileNode.addEventListener('DOMNodeInserted',function(e){ var m=mobileNode.innerText; window.chrome.webview.postMessage(m);}); |
|||
document.getElementById('viewOrderMobile').click();";
|
|||
_ = await wb2.CoreWebView2.ExecuteScriptAsync(js); |
|||
} |
|||
} |
|||
|
|||
private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e) |
|||
{ |
|||
var mobole = e.TryGetWebMessageAsString(); |
|||
this.Tag = mobole; |
|||
this.DialogResult = true; |
|||
this.Close(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,456 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Net; |
|||
using System.Net.Http; |
|||
using System.Threading; |
|||
|
|||
namespace BBWY.Common.Http |
|||
{ |
|||
/// <summary>
|
|||
/// Http下载器
|
|||
/// </summary>
|
|||
public class HttpDownloader |
|||
{ |
|||
|
|||
private IHttpClientFactory httpClientFactory; |
|||
|
|||
public HttpDownloader(IHttpClientFactory httpClientFactory, DownloadSetting dwSetting = null) |
|||
{ |
|||
this.httpClientFactory = httpClientFactory; |
|||
complateArgs = new DownloadCompletedEventArgs(); |
|||
changeArgs = new DownloadProgressChangedEventArgs(); |
|||
if (dwSetting == null) |
|||
dwSetting = new DownloadSetting(); |
|||
downloadSetting = dwSetting; |
|||
buffer = new byte[downloadSetting.BufferSize]; |
|||
} |
|||
|
|||
~HttpDownloader() |
|||
{ |
|||
this.buffer = null; |
|||
this.downloadSetting = null; |
|||
this.complateArgs.Error = null; |
|||
this.complateArgs = null; |
|||
this.changeArgs = null; |
|||
} |
|||
|
|||
#region Property
|
|||
|
|||
/// <summary>
|
|||
/// 下载进度变化参数
|
|||
/// </summary>
|
|||
private DownloadProgressChangedEventArgs changeArgs; |
|||
|
|||
/// <summary>
|
|||
/// 下载完成参数
|
|||
/// </summary>
|
|||
private DownloadCompletedEventArgs complateArgs; |
|||
|
|||
/// <summary>
|
|||
/// 下载参数配置类
|
|||
/// </summary>
|
|||
private DownloadSetting downloadSetting; |
|||
|
|||
/// <summary>
|
|||
/// 下载缓冲区
|
|||
/// </summary>
|
|||
private byte[] buffer; |
|||
|
|||
#endregion
|
|||
|
|||
#region Delegate
|
|||
public delegate void DownloadProgressChangedEventHandler(object sender, DownloadProgressChangedEventArgs e); |
|||
|
|||
public delegate void DownloadCompletedEventHandler(object sender, DownloadCompletedEventArgs e); |
|||
|
|||
public delegate void ReDownloadEventHandler(object sender, DownloadCompletedEventArgs e); |
|||
#endregion
|
|||
|
|||
#region Event
|
|||
/// <summary>
|
|||
/// 下载进度变化事件
|
|||
/// </summary>
|
|||
public event DownloadProgressChangedEventHandler OnDownloadProgressChanged; |
|||
|
|||
/// <summary>
|
|||
/// 下载完成事件
|
|||
/// </summary>
|
|||
public event DownloadCompletedEventHandler OnDownloadComplated; |
|||
|
|||
/// <summary>
|
|||
/// 自动重下事件
|
|||
/// </summary>
|
|||
public event ReDownloadEventHandler OnReDownload; |
|||
#endregion
|
|||
|
|||
#region Method
|
|||
/// <summary>
|
|||
/// 设置下载参数
|
|||
/// </summary>
|
|||
/// <param name="dwSetting"></param>
|
|||
public void SetDownloadSetting(DownloadSetting dwSetting) |
|||
{ |
|||
if (dwSetting != null) |
|||
downloadSetting = dwSetting; |
|||
} |
|||
|
|||
private void DoProcessChangedEvent(DownloadProgressChangedEventArgs args) |
|||
{ |
|||
OnDownloadProgressChanged?.Invoke(this, args); |
|||
} |
|||
|
|||
private void DoCompletedEvent(DownloadCompletedEventArgs args) |
|||
{ |
|||
OnDownloadComplated?.Invoke(this, args); |
|||
} |
|||
|
|||
private void DoReDownloadEvent(DownloadCompletedEventArgs args) |
|||
{ |
|||
OnReDownload?.Invoke(this, args); |
|||
} |
|||
|
|||
private void ArgsInit() |
|||
{ |
|||
changeArgs.Cancel = false; |
|||
complateArgs.Cancelled = false; |
|||
complateArgs.Error = null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取文件总大小
|
|||
/// </summary>
|
|||
/// <param name="url"></param>
|
|||
/// <returns></returns>
|
|||
public long GetTotalLength(string url) |
|||
{ |
|||
long length = 0; |
|||
try |
|||
{ |
|||
using (var httpClient = httpClientFactory.CreateClient()) |
|||
{ |
|||
var requestMessage = new HttpRequestMessage(HttpMethod.Head, url); |
|||
var httpResponse = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).Result; |
|||
if (httpResponse.IsSuccessStatusCode) |
|||
length = httpResponse.Content.Headers.ContentLength ?? 0; |
|||
} |
|||
|
|||
//var req = (HttpWebRequest)WebRequest.Create(new Uri(url));
|
|||
//req.Method = "HEAD";
|
|||
//req.Timeout = 5000;
|
|||
//var res = (HttpWebResponse)req.GetResponse();
|
|||
//if (res.StatusCode == HttpStatusCode.OK)
|
|||
//{
|
|||
// length = res.ContentLength;
|
|||
//}
|
|||
//res.Close();
|
|||
return length; |
|||
} |
|||
catch (WebException wex) |
|||
{ |
|||
throw wex; |
|||
} |
|||
} |
|||
|
|||
|
|||
private bool DownloadFile(string url, string savePath, long startPosition, long totalSize) |
|||
{ |
|||
long currentReadSize = 0; //当前已经读取的字节数
|
|||
if (startPosition != 0) |
|||
currentReadSize = startPosition; |
|||
using (var httpClient = httpClientFactory.CreateClient()) |
|||
{ |
|||
try |
|||
{ |
|||
httpClient.Timeout = new TimeSpan(0, 0, 20); |
|||
if (currentReadSize != 0 && currentReadSize == totalSize) |
|||
{ |
|||
changeArgs.CurrentSize = changeArgs.TotalSize = totalSize; |
|||
return true; |
|||
} |
|||
if (currentReadSize != 0) |
|||
{ |
|||
try |
|||
{ |
|||
httpClient.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(currentReadSize, totalSize); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
//http 416
|
|||
currentReadSize = 0; |
|||
} |
|||
} |
|||
|
|||
using (var response = httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result) |
|||
{ |
|||
using (var responseStream = response.Content.ReadAsStreamAsync().Result) |
|||
{ |
|||
changeArgs.TotalSize = totalSize; |
|||
using (var fs = new FileStream(savePath, currentReadSize == 0 ? FileMode.Create : FileMode.Append, FileAccess.Write)) |
|||
{ |
|||
//判断服务器是否支持断点续下
|
|||
if (currentReadSize != 0 && |
|||
response.StatusCode == HttpStatusCode.PartialContent && |
|||
response.Content.Headers.ContentLength != totalSize) |
|||
fs.Seek(startPosition, SeekOrigin.Begin); //支持,从本地文件流末尾进行写入
|
|||
else |
|||
currentReadSize = 0; //不支持,从本地文件流开始进行写入
|
|||
|
|||
if (buffer.Length != downloadSetting.BufferSize) |
|||
buffer = new byte[downloadSetting.BufferSize]; |
|||
int size = responseStream.Read(buffer, 0, buffer.Length); |
|||
while (size != 0) |
|||
{ |
|||
fs.Write(buffer, 0, size); |
|||
if (buffer.Length != downloadSetting.BufferSize) |
|||
buffer = new byte[downloadSetting.BufferSize]; |
|||
size = responseStream.Read(buffer, 0, buffer.Length); |
|||
currentReadSize += size; //累计下载大小
|
|||
//执行下载进度变化事件
|
|||
changeArgs.CurrentSize = currentReadSize; |
|||
DoProcessChangedEvent(changeArgs); |
|||
//判断挂起状态
|
|||
if (changeArgs.Cancel) |
|||
return true; |
|||
} |
|||
|
|||
//执行下载进度变化事件
|
|||
changeArgs.CurrentSize = changeArgs.TotalSize; |
|||
DoProcessChangedEvent(changeArgs); |
|||
fs.Flush(true); |
|||
} |
|||
|
|||
//验证远程服务器文件字节数和本地文件字节数是否一致
|
|||
long localFileSize = 0; |
|||
try |
|||
{ |
|||
localFileSize = new FileInfo(savePath).Length; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
localFileSize = changeArgs.CurrentSize; |
|||
} |
|||
|
|||
if (totalSize != localFileSize) |
|||
{ |
|||
complateArgs.Error = new Exception(string.Format("远程文件字节:[{0}]与本地文件字节:[{1}]不一致", totalSize, localFileSize)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
catch (IOException ex) |
|||
{ |
|||
complateArgs.Error = ex; |
|||
} |
|||
catch (WebException ex) |
|||
{ |
|||
complateArgs.Error = ex; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
complateArgs.Error = ex; |
|||
} |
|||
} |
|||
return complateArgs.Error == null; |
|||
} |
|||
|
|||
|
|||
public bool DownloadFile(string url, string saveFolderPath, string saveFileName, long? totalSize) |
|||
{ |
|||
ArgsInit(); |
|||
var result = false; |
|||
//验证文件夹
|
|||
try |
|||
{ |
|||
if (!Directory.Exists(saveFolderPath)) |
|||
Directory.CreateDirectory(saveFolderPath); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
complateArgs.Error = ex; |
|||
DoCompletedEvent(complateArgs); |
|||
return result; |
|||
} |
|||
|
|||
if (totalSize == null || totalSize.Value == 0) |
|||
{ |
|||
try |
|||
{ |
|||
totalSize = GetTotalLength(url); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Console.WriteLine("获取远程服务器字节数失败 {0}", ex.Message); |
|||
complateArgs.Error = ex; |
|||
DoCompletedEvent(complateArgs); |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
string saveFilePath = Path.Combine(saveFolderPath, saveFileName); |
|||
long startPosition = 0; |
|||
for (var i = 1; i <= downloadSetting.TryCount; i++) |
|||
{ |
|||
if (File.Exists(saveFilePath)) |
|||
{ |
|||
try |
|||
{ |
|||
startPosition = new FileInfo(saveFilePath).Length; |
|||
} |
|||
catch |
|||
{ |
|||
startPosition = 0; |
|||
} |
|||
} |
|||
|
|||
result = DownloadFile(url, saveFilePath, startPosition, totalSize.Value); |
|||
if (result) |
|||
{ |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
if (i != downloadSetting.TryCount) |
|||
{ |
|||
complateArgs.TryCount = i + 1; |
|||
DoReDownloadEvent(complateArgs); |
|||
Thread.Sleep(downloadSetting.SleepTime); |
|||
if (complateArgs.Cancelled) |
|||
break; |
|||
ArgsInit(); |
|||
} |
|||
} |
|||
if (complateArgs.Cancelled) |
|||
break; |
|||
} |
|||
DoCompletedEvent(complateArgs); |
|||
return result; |
|||
} |
|||
|
|||
public byte[] DwonloadBytes(string url) |
|||
{ |
|||
ArgsInit(); |
|||
using (var httpClient = httpClientFactory.CreateClient()) |
|||
{ |
|||
return httpClient.GetByteArrayAsync(url).Result; |
|||
} |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 取消/暂停下载
|
|||
/// </summary>
|
|||
public void CancelDownload() |
|||
{ |
|||
this.changeArgs.Cancel = true; |
|||
this.complateArgs.Cancelled = true; |
|||
} |
|||
#endregion
|
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 下载进度变化参数
|
|||
/// </summary>
|
|||
public class DownloadProgressChangedEventArgs |
|||
{ |
|||
public DownloadProgressChangedEventArgs() |
|||
{ |
|||
ProgressPercentage = 0.0; |
|||
Cancel = false; |
|||
} |
|||
/// <summary>
|
|||
/// 下载进度百分比
|
|||
/// </summary>
|
|||
public double ProgressPercentage; |
|||
|
|||
|
|||
private long currentSize; |
|||
|
|||
/// <summary>
|
|||
/// 当前下载总大小
|
|||
/// </summary>
|
|||
public long CurrentSize |
|||
{ |
|||
get { return currentSize; } |
|||
set |
|||
{ |
|||
currentSize = value; |
|||
this.ProgressPercentage = Math.Round((CurrentSize * 1.0 / TotalSize) * 100, 2); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 文件总大小
|
|||
/// </summary>
|
|||
public long TotalSize; |
|||
|
|||
/// <summary>
|
|||
/// 取消状态
|
|||
/// </summary>
|
|||
public bool Cancel; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 下载完成参数
|
|||
/// </summary>
|
|||
public class DownloadCompletedEventArgs |
|||
{ |
|||
public DownloadCompletedEventArgs() |
|||
{ |
|||
Cancelled = false; |
|||
Error = null; |
|||
} |
|||
/// <summary>
|
|||
/// 下载异常
|
|||
/// </summary>
|
|||
public Exception Error; |
|||
|
|||
/// <summary>
|
|||
/// 重试次数
|
|||
/// </summary>
|
|||
public int TryCount; |
|||
|
|||
/// <summary>
|
|||
/// 下载操作是否被取消 【取消则为true;默认false】
|
|||
/// </summary>
|
|||
public bool Cancelled; |
|||
} |
|||
|
|||
public class DownloadSetting |
|||
{ |
|||
public DownloadSetting() |
|||
{ |
|||
this.BufferSize = 1024 * 1024 * 1; |
|||
this.TryCount = 5; |
|||
this.SleepTime = 5000; |
|||
} |
|||
|
|||
/// <summary>
|
|||
///
|
|||
/// </summary>
|
|||
/// <param name="bufferSize"></param>
|
|||
/// <param name="tryCount"></param>
|
|||
/// <param name="sleepTime">毫秒</param>
|
|||
public DownloadSetting(int bufferSize, int tryCount, int sleepTime) |
|||
{ |
|||
this.BufferSize = bufferSize; |
|||
this.TryCount = tryCount; |
|||
this.SleepTime = sleepTime; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 下载缓冲区大小
|
|||
/// </summary>
|
|||
public int BufferSize; |
|||
|
|||
/// <summary>
|
|||
/// 重试次数
|
|||
/// </summary>
|
|||
public int TryCount; |
|||
|
|||
/// <summary>
|
|||
/// 自动重下休眠时间, 毫秒
|
|||
/// </summary>
|
|||
public int SleepTime; |
|||
} |
|||
} |
Loading…
Reference in new issue