Custom WOPI Implementation - ms-wopi

I am trying to implement previews(WOPI) for my files stored in local file system. I am trying to implement it using the Office Online Server Farm we have. I used the below code but its calling the "Get" endpoint but after that its not calling the "contents" end point.
URL - http://ServerName/wv/wordviewerframe.aspx?ui=1033&rs=1033&dchat=false&hid=1&IsLicensedUser=1&WOPISrc=http://WOPIHost:8082/wopi/files/00000000-0000-0000-0000-000000000000&access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6InhYbFQwSUp4MlZCVEJFeVFMdGtFOFY2ZkhwZyJ9%2EeyJhdWQiOiJ3b3BpL3F1aW50aWxlcy5zaGFyZXBvaW50LmNvbUA1OTg5ZWNlMC1mOTBlLTQwYmYtOWM3OS0xYTdiZWNjZGI4NjEiLCJpc3MiOiIwMDAwMDAwMy0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDBAOTAxNDAxMjItODUxNi0xMWUxLThlZmYtNDkzMDQ5MjQwMTliIiwibmJmIjoiMTU4MzIxOTgwNCIsImV4cCI6IjE1ODMyNTU4MDQiLCJuYW1laWQiOiIwIy5mfG1lbWJlcnNoaXB8Z29rdWwuYWdAaW4uaW1zaGVhbHRoLmNvbSIsIm5paSI6Im1pY3Jvc29mdC5zaGFyZXBvaW50IiwiaXN1c2VyIjoidHJ1ZSIsImNhY2hla2V5IjoiMGguZnxtZW1iZXJzaGlwfDEwMDMzZmZmOWIxNjZlNmNAbGl2ZS5jb20iLCJzaWduaW5fc3RhdGUiOiJbXCJrbXNpXCIsXCJkdmNfZG1qZFwiXSIsImlzbG9vcGJhY2siOiJUcnVlIiwiYXBwY3R4IjoiMjBhMTViZGM2Y2QyNDRjMzkyMzNjYjQxNDFiNDc1OTU7dlhqbUZlRWpsc2p4TTFaeTMxT2ZFVmlKQUUwPTtEZWZhdWx0Ozs3RkZGRkZGRkZGRkZGRkZGO1RydWU7OzswO2RlMTYzYjlmLWEwMTgtYTAwMC1mZWRiLTQ1MzBmN2Q0MjYwMSJ9%2EXmvaQMvtq0ClU1rHW%5FibIx7OjQ7nbmXVO9Bs3JmH%2DCqxdxtaJKKqC9sd3j2cjfFIIsYFw%2DOpoZ6rpp5ijcl3WwWJWX0uR%2DsgdAi4If49dQnbDDunvLdCuKl%2D7PFc96M60ByVa0jbywUvFW8FhoR2bPdVMBYiILC5oExEkOc4BCGgWoUNE9n%2Dv74fWJrFbJFtMVaof3n%2DQCQHy8SXh%5F3O2SaSVw9bMPYdELSbPnvqsz4l8mUrEbN%2Dhs3kW2n3d1nSuhjcEn8JyMZUrFk%5Fxl2GEbGh8A2KavTql1W5MBlXPzL2r4Ynn1A3XTguYcsieF%5FORhCemm%5FMFbDGMgUvlb%2Dkwg&access_token_ttl=1583752281063
{
[WopiTokenValidationFilter]
[HttpGet]
[Route("wopi/files/{id}")]
public async Task<HttpResponseMessage> Get(Guid id)
{
//Handles CheckFileInfo
return await HttpContext.Current.ProcessWopiRequest();
}
[WopiTokenValidationFilter]
[HttpGet]
[Route("wopi/files/{id}/contents")]
public async Task<HttpResponseMessage> Contents(Guid id)
{
//Handles GetFile
return await HttpContext.Current.ProcessWopiRequest();
}
[WopiTokenValidationFilter]
[HttpPost]
[Route("wopi/files/{id}")]
public async Task<HttpResponseMessage> Post(Guid id)
{
//Handles Lock, GetLock, RefreshLock, Unlock, UnlockAndRelock, PutRelativeFile, RenameFile, PutUserInfo
return await HttpContext.Current.ProcessWopiRequest();
}
[WopiTokenValidationFilter]
[HttpPost]
[Route("wopi/files/{id}/contents")]
public async Task<HttpResponseMessage> PostContents(Guid id)
{
//Handles PutFile
return await HttpContext.Current.ProcessWopiRequest();
}
}```

Finally I identified the issue. The Version field should be string like "1.0.0.0" instead of int.

This is the response - {"UserId":"user#domain.com","CloseUrl":"https://<server>:8082","HostEditUrl":"http://<server>/we/wordeditorframe.aspx?ui=1033&rs=1033&dchat=false&hid=1&IsLicensedUser=1&WOPISrc=http://<server>:8082/wopi/files/00000000-0000-0000-0000-000000000000","HostViewUrl":"http://<server>/wv/wordviewerframe.aspx?ui=1033&rs=1033&dchat=false&hid=1&IsLicensedUser=1&WOPISrc=http://<server>:8082/wopi/files/00000000-0000-0000-0000-000000000000","SupportsCoauth":false,"SupportsExtendedLockLength":false,"SupportsFileCreation":false,"SupportsFolders":false,"SupportsGetLock":true,"SupportsLocks":true,"SupportsRename":true,"SupportsScenarioLinks":false,"SupportsSecureStore":false,"SupportsUpdate":true,"SupportsUserInfo":true,"LicensesCheckForEditIsEnabled":true,"ReadOnly":false,"RestrictedWebViewOnly":false,"UserCanAttend":false,"UserCanNotWriteRelative":false,"UserCanPresent":false,"UserCanRename":true,"UserCanWrite":true,"WebEditingDisabled":false,"Actions":null,"id":"00000000-0000-0000-0000-000000000000","LockValue":null,"LockExpires":null,"OwnerId":"user#domain.com","BaseFileName":"Test.docx","Container":null,"Size":102400,"Version":1,"UserInfo":null}

Related

Asp.Net-Core + MongoDb - How to search database by "code" and return the original url?

I am unsure how to go about searching for the "Code" stored in my Database in order to return the "OriginalUrl".
I know I can search for the ObjectId but I want to be able to search by the "Code" assigned to that ObjectId.
Currently I have a working program that takes a Url as well as a "title" and sends it to the database:
It is assigned an Objectid _id and a randomly generated 12 character "Code":
If it helps this is my Controller class:
namespace ShortenUrls.Controllers
{
[Route("api/codes")]
public class ShortUrlsController : Controller
{
private readonly ShortUrlRepository _repo;
public ShortUrlsController(ShortUrlRepository repo)
{
_repo = repo;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
var su = await _repo.GetAsync(id);
if (su == null)
return NotFound();
return Ok(su);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] ShortUrl su)
{
await _repo.CreateAsync(su);
return Ok(su);
}
}
And Repository class:
namespace ShortenUrls.Models.Repository
{
public class ShortUrlRepository
{
private const string alphabet = "23456789bcdfghjkmnpqrstvwxyz-_";
private static readonly Random rand = new Random();
private readonly Database _db;
public ShortUrlRepository(Database db)
{
_db = db;
}
private static string GenerateCode()
{
const int codeLength = 12;
var chars = new char[codeLength];
for (var i = 0; i < codeLength; i++)
{
chars[i] = alphabet[rand.Next(0, alphabet.Length)];
}
return new string(chars);
}
public Task<ShortUrl> GetAsync(string id)
{
var objId = ObjectId.Parse(id);
return _db.Urls.Find(x => x.Id == objId).FirstOrDefaultAsync();
}
public Task CreateAsync(ShortUrl su)
{
su.Code = GenerateCode();
return _db.Urls.InsertOneAsync(su);
}
}
Just use a filter. Doing it this way let's you create a query specifically for the "code".
public async Task<ShortUrl> GetAsync(string code)
{
var filterBuilder = new FilterDefinitionBuilder<ShortUrl>();
var filter = filterBuilder.Eq(s => s.Code, code);
var cursor = await _db.Urls.FindAsync(filter);
return await cursor.FirstOrDefaultAsync();
}
Assuming you already know the code when calling this and that ObjectId is created on InsertOneAsync call. First change your repository to take Code as searchable input.
public Task<ShortUrl> GetAsync(string code)
{
return await _db.Urls.FirstOrDefaultAsync(x => x.Code == code);
}
Then change your controller Get to this:
[HttpGet("{code}")]
public async Task<IActionResult> Get(string code)
{
var su = await _repo.GetAsync(code);
if (su == null)
return NotFound();
return Ok(su);
}
In your controller you can access su.OriginalUrl if you need to only return that after getting the object.
Then in postman you can just call http://localhost:51767/api/codes?code=cmg3fjjr_gtv
Remember only Id works for default url parameters as setup by your default routes in Startup.cs.
app.UseMvc(routes => { /*...*/ })
So this wont work: /api/codes/cmg3fjjr_gtv unless you specifically set up routing or change {code} back to {id}. Readability of your code suffers though.

InvokeApiAsync<HttpResponseMessage> returns null

Can someone explain my why that client (Xamarin.Forms PCL) call returns null?
HttpResponseMessage response = await OfflineSyncStoreManager.Instance.MobileAppClient.InvokeApiAsync<HttpResponseMessage>("ResetTruckAuftragWorkflow");
response is null. When I execute that in a console app it returns the
valid http response.
I use the latest stable ZUMO nugets in client and backend. There is my ZUMO backend code:
[Authorize]
[MobileAppController]
public class ResetTruckAuftragWorkflowController : ApiController
{
private readonly RcsMobileContext _rcsMobileContext;
private readonly TruckFahrerInfo _truckFahrerInfo;
public ResetTruckAuftragWorkflowController()
{
_rcsMobileContext = new RcsMobileContext();
_truckFahrerInfo = new TruckFahrerInfo(this.User as ClaimsPrincipal);
}
// POST api/ResetTruckAuftragWorkflow
[HttpPost]
public async Task<IHttpActionResult> PostAsync()
{
if (ModelState.IsValid)
{
using (var transaction = _rcsMobileContext.Database.BeginTransaction())
{
try
{
var truckAuftragList = _rcsMobileContext.TruckAuftrags.PerUserFilter(_truckFahrerInfo.FahrerId);
var truckAppIds = truckAuftragList?.Select(ta => ta.TruckAppId).ToArray();
if (truckAppIds != null)
{
foreach (var truckAppId in truckAppIds)
{
await _rcsMobileContext.Database.ExecuteSqlCommandAsync(_tawQueryTaskStatus10, truckAppId);
await _rcsMobileContext.Database.ExecuteSqlCommandAsync(_tawQueryTaskStatus5, truckAppId);
await _rcsMobileContext.Database.ExecuteSqlCommandAsync(_talQuery, truckAppId);
await _rcsMobileContext.Database.ExecuteSqlCommandAsync(_taQuery, truckAppId);
}
}
await _rcsMobileContext.Database.ExecuteSqlCommandAsync(_taQuery, _truckFahrerInfo.FahrerId);
transaction.Commit();
}
catch (Exception e)
{
transaction.Rollback();
return BadRequest($"Transaction failed: {e}");
}
}
return Ok();
}
else
{
return BadRequest(ModelState);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_rcsMobileContext.Dispose();
}
base.Dispose(disposing);
}
}
thanks
Eric
InvokeApiAsync decodes the body that is returned and de-serializes the JSON into type T. You should not use HttpResponseMessage for this purpose as it is not serializable.
If you don't care about the body, use the non-generic form of InvokeApiAsync.

Two factor auth with IdentityServer3 - remember browser

I'm implementing 2fa with IdentityServer3 + Asp.Net Identity (2.2.1). I'm stuck on the 2fa implementation. I've looked at the "AspNetIdentity_2fa" sample, which helped a lot.
I have everything wired up, except for the cookie that indicates the browser has been successfully authenticated. I can set the cookie during the code confirmation, but I cannot get to the cookie in the PostAuthenticateLocalAsync() call to see whether or not to take the 2fa path.
protected override Task<AuthenticateResult> PostAuthenticateLocalAsync(User user, SignInMessage message)
{
if (user.TwoFactorEnabled) // && !TwoFactorCookieSet...
{
return Task.FromResult(new AuthenticateResult("/auth/sendcode", user.Id, user.DisplayName));
}
return base.PostAuthenticateLocalAsync(user, message);
}
I believe I'm taking the correct approach in using the partial logins, but how would I detect that the current browser has already been approved?
More detail: the /auth/sendcode is the standard Asp.Net Identity pages/flow for 2fa, combined with the partial login logic from the sample.
Okay, I found that OwinEnvironmentService can be injected into IdentityServer services. I can get the cookies via OwinEnvironmentService. I'd be interested to hear any opinions on this solution (this isn't meant to be production-ready, it's just a concept):
internal class UserService : AspNetIdentityUserService<User, string>
{
private readonly OwinEnvironmentService _owinEnvironmentService;
public UserService(UserManager userMgr, OwinEnvironmentService owinEnvironmentService) : base(userMgr)
{
_owinEnvironmentService = owinEnvironmentService;
DisplayNameClaimType = IdentityServer3.Core.Constants.ClaimTypes.Name;
}
protected override Task<AuthenticateResult> PostAuthenticateLocalAsync(User user, SignInMessage message)
{
if (user.TwoFactorEnabled)
{
var twoFactorNeeded = false;
object httpContext;
if (_owinEnvironmentService.Environment.TryGetValue("System.Web.HttpContextBase", out httpContext))
{
var cookies = (httpContext as HttpContext)?.Request.Cookies;
if (cookies != null && !cookies.AllKeys.Contains(IdentityConstants.CookieNames.TwoFactorCompleted)) twoFactorNeeded = true;
}
if (twoFactorNeeded)
return Task.FromResult(new AuthenticateResult("/auth/sendcode", user.Id, user.DisplayName));
}
return base.PostAuthenticateLocalAsync(user, message);
}
}
UPDATED
Based on Brock's comment, I think I have a better solution.
// custom User Service
internal class UserService : AspNetIdentityUserService<User, string>
{
private readonly OwinEnvironmentService _owinEnvironmentService;
public UserService(UserManager userMgr, OwinEnvironmentService owinEnvironmentService) : base(userMgr)
{
_owinEnvironmentService = owinEnvironmentService;
DisplayNameClaimType = IdentityServer3.Core.Constants.ClaimTypes.Name;
}
protected override async Task<AuthenticateResult> PostAuthenticateLocalAsync(User user, SignInMessage message)
{
if (user.TwoFactorEnabled)
{
var owinContext = new OwinContext(_owinEnvironmentService.Environment);
var result = await owinContext.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
if(result == null) return new AuthenticateResult("/auth/sendcode", user.Id, user.DisplayName);
}
return await base.PostAuthenticateLocalAsync(user, message);
}
}
// (in MVC controller) generate the 2FA security code and send it
public async Task<ActionResult> SendCode(SendCodeViewModel model)
{
// ...some code removed for brevity...
var token = await UserManager.GenerateTwoFactorTokenAsync(userId, model.SelectedProvider);
var identityResult = await UserManager.NotifyTwoFactorTokenAsync(userId, model.SelectedProvider, token);
if (!identityResult.Succeeded) return View("Error");
return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, model.ReturnUrl, model.RememberMe });
}
// (in MVC controller) verify the code and sign in with 2FA
public async Task<ActionResult> VerifyCode(VerifyCodeViewModel model)
{
// ...some code removed for brevity...
var signInManager = new SignInManager<User, string>(UserManager, Request.GetOwinContext().Authentication);
if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, model.Provider, model.Code))
{
await UserManager.ResetAccessFailedCountAsync(user.Id);
await signInManager.SignInAsync(user, model.RememberMe, model.RememberBrowser);
var resumeUrl = await env.GetPartialLoginResumeUrlAsync();
return Redirect(resumeUrl);
}
else
{
await UserManager.AccessFailedAsync(user.Id);
ModelState.AddModelError("", "Invalid code.");
return View(model);
}
}
I implemented the same for remember browser requirement however following statement return always null when we logout and login again.so twofactory step is not skipped..
var result = await owinContext.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

OData V4 REST using GUID primary key

all! I am using OData v4 building REST services. My tables have a GUID primary key.
My GET and POST requests are working fine. But the PUT, PATCH, and DELETE requests fail with 404.
I am not sure what the url should look like. I've tried these in Fiddler, all getting the 404. I have googled this quite a bit with no luck.
http://localhost/ershubrest/AppVersions/guid'00000000-e90f-4938-b8f6-000000000000'
http://localhost/ershubrest/AppVersions/'00000000-e90f-4938-b8f6-000000000000'
http://localhost/ershubrest/AppVersions/00000000-e90f-4938-b8f6-000000000000
Here is the code for my controller...
using ERSHubRest.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Query;
using System.Web.OData.Routing;
namespace ERSHubRest.controllers
{
[ODataRoutePrefix("AppVersions")]
public class AppVersionsController : ODataController
{
HubModel db = new HubModel();
private bool AppVersionsExists(System.Guid key)
{
return db.AppVersions.Any(p => p.AppVersionId == key);
}
// http GET for select queries
[ODataRoute]
[EnableQuery]
public IQueryable<AppVersions> Get()
{
return db.AppVersions;
}
[ODataRoute("({key})")]
[EnableQuery]
public IHttpActionResult Get([FromODataUri] System.Guid key)
{
IQueryable<AppVersions> result = db.AppVersions.Where(p => p.BusinessId == key);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
// http POST for insert
[ODataRoute()]
[HttpPost]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Post(AppVersions appVersions)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.AppVersions.Add(appVersions);
await db.SaveChangesAsync();
return Created(appVersions);
}
// http PUT and PATCH for updates
[ODataRoute()]
[HttpPatch]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Patch([FromODataUri] System.Guid key, Delta<AppVersions> appVersions)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var entity = await db.AppVersions.FindAsync(key);
if (entity == null)
{
return NotFound();
}
appVersions.Patch(entity);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AppVersionsExists(key) )
{
return NotFound();
}
else
{
throw;
}
}
return Updated(entity);
}
[ODataRoute()]
[HttpPut]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Put([FromODataUri] System.Guid key, AppVersions update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if ( ! key.Equals( update.BusinessId ))
{
return BadRequest();
}
if (!AppVersionsExists(key))
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if ( ! AppVersionsExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
// last is Delete
[ODataRoute()]
[HttpDelete]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public async Task<IHttpActionResult> Delete([FromODataUri] System.Guid key)
{
var appVersions = await db.AppVersions.FindAsync(key);
if (appVersions == null)
{
return NotFound();
}
db.AppVersions.Remove(appVersions);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
// clean up
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
The request URL for PATCH, PUT and DELETE should be:
http://localhost/ershubrest/AppVersions(00000000-e90f-4938-b8f6-000000000000)
OData is using parenthesizes for addressing single entities using keys.
For more URL conventions, the OData V4 URL convention spec can be referred to: http://docs.oasis-open.org/odata/odata/v4.0/os/part2-url-conventions/odata-v4.0-os-part2-url-conventions.html
Try this:
http://localhost/ershubrest/AppVersions(guid'00000000-e90f-4938-b8f6-000000000000')
That should work!!
Odata V1-3 : http://localhost/ershubrest/AppVersions(guid'00000000-e90f-4938-b8f6-000000000000')
Odata V4 : http://localhost/ershubrest/AppVersions(00000000-e90f-4938-b8f6-000000000000)
I've tested Odata for 2 days
I ensure that !

Consuming Web API from MVC4 controller?

I am currently working on a website and I had a good separation of concerns following a repository pattern with repositories and managers. Now, I am attempting to implement a Web API as I would greatly benefit from it in the future being able to use it from various clients. Since I am fairly new to REST services, I am having trouble with the correct procedure to consume my web API from a Service in my MVC4 application to then use that service in my MVC controllers. I do not want to have to use knockout for every call to the API.
My Web APIs look something like this(simplified):
public class UserController : ApiController
{
private readonly IUserManager _manager;
public UserController(IUserManager manager)
{
this._manager = manager;
}
// GET api/user
public IEnumerable<User> Get()
{
return _manager.GetAll();
}
// GET api/user/5
public User Get(int id)
{
return _manager.GetById(id);
}
// POST api/user
public void Post(User user)
{
_manager.Add(user);
}
// PUT api/user/5
public void Put(User user)
{
_manager.Update(user);
}
// DELETE api/user/5
public void Delete(User user)
{
_manager.Delete(user);
}
}
I essentially would like to create a service to consume my web API as such:
public class UserService : IUserService
{
....Implement something to get,post,put,and delete using the api.
}
so then I can use it in my mvc controller:
public class UserController: Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
this._userService = userService;
}
//And then I will be able to communicate with my WebAPI from my MVC controller
}
I know this is possible because I have seen it done at some workplaces but it is very difficult to find articles about this, I have only found articles explaining how to consume web API through knockout. Any help or tips would be greatly appreciated.
Have a look at the implementation over here: https://github.com/NBusy/NBusy.SDK/blob/master/src/NBusy.Client/Resources/Messages.cs
It basically makes use of HttpClient class to consume Web API. One caveat though, all responses are wrapped in a custom HttpResponse class in that sample. You don't need to do that and can simply use the retrieved DTO object as the return type or a raw HttpResponseMessage class.
You might want to create a static class, I created a separate Class Library to use across solutions that might want to use the API.
NOTE: I use RestSharp for POST and PUT operation since I haven't been able to get them to work using the regular HttpClient over SSL. As you can see documented in this question.
internal static class Container
{
private static bool isInitialized;
internal static HttpClient Client { get; set; }
internal static RestClient RestClient { get; set; }
/// <summary>
/// Verifies the initialized.
/// </summary>
/// <param name="throwException">if set to <c>true</c> [throw exception].</param>
/// <returns>
/// <c>true</c> if it has been initialized; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="System.InvalidOperationException">Service must be initialized first.</exception>
internal static bool VerifyInitialized(bool throwException = true)
{
if (!isInitialized)
{
if (throwException)
{
throw new InvalidOperationException("Service must be initialized first.");
}
}
return true;
}
/// <summary>
/// Initializes the Service communication, all methods throw a System.InvalidOperationException if it hasn't been initialized.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="connectionUserName">Name of the connection user.</param>
/// <param name="connectionPassword">The connection password.</param>
internal static void Initialize(string url, string connectionUserName, string connectionPassword)
{
RestClient = new RestClient(url);
if (connectionUserName != null && connectionPassword != null)
{
HttpClientHandler handler = new HttpClientHandler
{
Credentials = new NetworkCredential(connectionUserName, connectionPassword)
};
Client = new HttpClient(handler);
RestClient.Authenticator = new HttpBasicAuthenticator(connectionUserName, connectionPassword);
}
else
{
Client = new HttpClient();
}
Client.BaseAddress = new Uri(url);
isInitialized = true;
}
}
public static class UserService
{
public static void Initialize(string url = "https://serverUrl/", string connectionUserName = null, string connectionPassword = null)
{
Container.Initialize(url, connectionUserName, connectionPassword);
}
public static async Task<IEnumerable<User>> GetServiceSites()
{
// RestSharp example
Container.VerifyInitialized();
var request = new RestRequest("api/Users", Method.GET);
request.RequestFormat = DataFormat.Json;
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute<List<User>>(request); }).ConfigureAwait(false);
return response.Data;
// HttpClient example
var response = await Container.Client.GetAsync("api/Users/").ConfigureAwait(false);
return await response.Content.ReadAsAsync<IEnumerable<User>>().ConfigureAwait(false);
}
public static async Task<User> Get(int id)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users/" + id, Method.GET);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute<User>(request); }).ConfigureAwait(false);
return response.Data;
}
public static async Task Put(int id, User user)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users/" + id, Method.PATCH);
request.RequestFormat = DataFormat.Json;
request.AddBody(user);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
}
public static async Task Post(User user)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(user);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
}
public static async Task Delete(int id)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users/" + id, Method.DELETE);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
}
}