1. 程式人生 > 其它 >從零開始搭建Wpf基礎7-Api資料接入

從零開始搭建Wpf基礎7-Api資料接入

前言:使用HttpClient獲取Api資料。

第一步:對獲取資料結構進行規劃,我們還是採用經典的Business作為中間層,HttpClient等底層請求資料的方法放在Service層。

ViewModel -> Business -> Service

第二步:HttpClient的使用httpClientFactory.CreateClient()來獲取,避免埠號未能及時釋放導致耗盡的情況,我們用單例來構造HttpClientHelper。

publicclassHttpClientHelper
{
privatestaticHttpClientHelperinstance=null;
privatestaticobjectobj=newobject();
privateIHttpClientFactoryhttpClientFactory;

publicstaticHttpClientHelperInstance
{
get
{
if(instance==null)
{
lock(obj)
{
if(instance==null)
{
instance=newHttpClientHelper();
varserviceProvider=newServiceCollection().AddHttpClient().BuildServiceProvider();
instance.httpClientFactory=serviceProvider.GetService<IHttpClientFactory>();
}
}
}
returninstance;
}
}

///<summary>
///記錄日誌
///</summary>
publicAction<string>HandleLog{get;set;}


///<summary>
///使用post方法非同步請求
///</summary>
///<paramname="url">目標連結</param>
///<paramname="json">傳送的引數字串,只能用json</param>
///<returns>返回的字串</returns>
publicasyncTask<string>PostAsyncJson(stringurl,stringjson,Dictionary<string,string>header=null,TimeSpan?timeSpan=null)
{
HttpClientclient=httpClientFactory.CreateClient();
if(timeSpan.HasValue)
{
client.Timeout=timeSpan.Value;
}
HttpContentcontent=newStringContent(json);
if(header!=null)
{
client.DefaultRequestHeaders.Clear();
foreach(variteminheader)
{
client.DefaultRequestHeaders.Add(item.Key,item.Value);
}
}
content.Headers.ContentType=newSystem.Net.Http.Headers.MediaTypeHeaderValue("application/json");

stringresponseBody=string.Empty;
stringresData=string.Empty;
DateTimestartTime=DateTime.Now;

try
{
HttpResponseMessageresponse=awaitclient.PostAsync(url,content);
response.EnsureSuccessStatusCode();
responseBody=awaitresponse.Content.ReadAsStringAsync();
resData=responseBody;
}
catch(Exceptionex)
{
resData=$"異常:{ExceptionHelper.GetExceptionAllMsg(ex)}";

throwex;
}
finally
{
vartime=DateTime.Now-startTime;
if(resData?.Length>1000)
{
resData=resData.Substring(0,1000);
resData+="......";
}

stringlog=
$@"方向:請求外部介面
url:{url}
method:{"Post"}
耗時:{(int)time.TotalMilliseconds}ms

返回:{resData}
";
HandleLog?.Invoke(log);
}

returnresponseBody;
}


}

第三步:我們需要兩個方法:一個登入的時候獲取Token的方法(使用jwt登入校驗,登入後服務返回一個密匙Token,客戶端用這個Token去訪問服務),一個Post請求資料的方法,如下:

publicclassApiDataProvider:IDataProvider
{
privatestringUrl{get;set;}
publicstringToken{get;set;}

//攜帶Token
publicDictionary<string,string>SetHeader()
{
Dictionary<string,string>header=newDictionary<string,string>();
header.Add("Authorization",string.Format("Bearer{0}",Token));

returnheader;
}

//獲取資料
publicasyncTask<AjaxResult<T>>GetData<T>(stringurl,stringjson="{}")
{
if(!url.StartsWith("http"))
{
url=Url+url;
}
varcontent=awaitHttpClientHelper.Instance.PostAsyncJson(url,json,SetHeader());
varresult=JsonConvert.DeserializeObject<AjaxResult<T>>(content);
returnresult;
}

//獲取Token
publicasyncTask<AjaxResult>GetToken(stringurl,stringuserName,stringpassword)
{
Url=url;

varcontent=awaitHttpClientHelper.Instance.PostAsyncJson((string.Format("{0}/Base_Manage/Home/SubmitLogin",Url)),JsonConvert.SerializeObject(new{userName=userName,password=password}));
varresult=JsonConvert.DeserializeObject<AjaxResult>(content);
Token=result.Dataasstring;

returnresult;
}

}

同樣我們用介面實現,好處是方便隨時切換資料獲取方法,比如HttpClient換成了WebSocket、SignalR,使用GetToken和GetData的地方是不用動的,只要實現WebSocketDataProvider就行了。

publicinterfaceIDataProvider
{
Task<AjaxResult>GetToken(stringurl,stringuserName,stringpassword);


//[LogHandler]
Task<AjaxResult<T>>GetData<T>(stringurl,stringjson="{}");
}

第四步:新增Core(有些也叫Util)工程,一些基礎公共的方法和類放在這裡,此處不在貼程式碼,暫時目錄結構如下:

第五步:修改登入頁面LoginViewModel的邏輯,使用_dataProvider.GetToken來實現登入。

IContainerExtension_container;
IRegionManager_regionManager;
IDataProvider_dataProvider;
publicLoginViewModel(IContainerExtensioncontainer,IRegionManagerregionManager,IDataProviderdataProvider)
{
_container=container;
_regionManager=regionManager;
_dataProvider=dataProvider;

Title="Login";
}
privateasyncvoidLogin()
{
if(!string.IsNullOrEmpty(UserName)&&!string.IsNullOrEmpty(Password))
{
varmD5Password=Password.ToMD5String();
vartoken=await_dataProvider.GetToken(ServerIP,UserName,mD5Password);
if(!token.Success)
{
MessageBox.Show(token.Msg);
return;
}

_regionManager.RequestNavigate("MainContentRegion",nameof(IntroduceView));

}
else
{
MessageBox.Show("請輸入使用者名稱或密碼!");
}


}

好了,執行看效果,很遺憾報錯,因為IDataProvider並沒有實現註冊,程式並不知道IDataProvider是用ApiDataProvider實現的,當然你直接new一個也是可以的_dataProvider = new ApiDataProvider()。這就違背了我們IOC的初衷了。

第六步:在App.xaml.cs中註冊IDataProvider。

protectedoverridevoidRegisterTypes(IContainerRegistrycontainerRegistry)
{
containerRegistry.Register<IDataProvider,ApiDataProvider>();
}

再次執行,效果上還是一樣的,但是我們成功的訪問了後臺。

後續:下一章將實現,將登入介面做成獨立視窗,登入後再顯示主視窗。

原始碼地址:https://gitee.com/akwkevin/aistudio.-wpf.-client.-stepby-step

另外推薦一下我的Wpf客戶端框架:https://gitee.com/akwkevin/aistudio.-wpf.-aclient

作者:竹天笑 互相學習,提高自己。 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利.