Reaktivno programiranje je asinhrono programska paradigma se ukvarjajo z podatkovni tokovi in širjenje sprememb. - Wikipedija
Ko preberete ta stavek, boste morda še vedno končali enako kot jaz, ko sem ga prvič prebral: Nikjer bližje razumevanju njegove pomembnosti. Še malo predanosti osnovnim konceptom in hitro boste razumeli njegov pomen. V bistvu bi si lahko o reaktivnem programiranju najprej mislili kot: »Programiranje na steroidih, ki temelji na dogodkih«. Predstavljajte si vodnik dogodkov kot tok in si oglejte vsako sprožitev vodnika kot novo referenčno točko v toku. Na kratko, kar na koncu dobite, je reaktivno programiranje.
Obstaja nekaj konceptov, ki jih boste morda želeli razumeti, preden se še malo poglobite v reaktivno programiranje. Opazovane so predmeti, ki vam omogočajo dostop do tokov, o katerih smo govorili. Njihov namen je, da vam omogočijo okno za podatke v toku. Ko se to okno odpre, lahko poglej na kakršen koli način, ki ga izberete z uporabo Operaterji na njem in se tako odločite, kdaj in kako bo vaša prijava reagira do potoka. Na koncu določite Opazovalci na nastalem toku, da določite dejanje, ki se bo zgodilo vsakič, ko tok odda novo referenčno točko.
V praksi to samo pomeni, da imate več nadzora nad načinom, kako se vaša aplikacija odziva na dogajanje, pa naj bo to vaš uporabnik, ki klikne gumb, vaša aplikacija prejme odgovor HTTP ali si opomore od izjem. Ko boste enkrat začeli videti prednosti uporabe reaktivnega programiranja (ki jih je veliko), se skoraj ne boste mogli več vrniti. To je preprosto zato, ker večina stvari, ki jih naredi aplikacija, reagira na določen način na določeno priložnost.
To zdaj še ne pomeni, da ta nov pristop nima slabih strani. Prvič, njegova krivulja učenja je lahko precej strma. Iz prve roke sem videl, kako se razvijalci (med drugim mladinci, upokojenci in arhitekti) trudijo, da bi ugotovili, kaj naj bi najprej napisali, v kakšnem vrstnem redu se izvaja njihova koda ali kako odpraviti napake. Pri prvem uvajanju teh konceptov priporočam, da pokažete veliko primerov. Ko bodo razvijalci začeli opazovati, kako naj bi stvari delovale in se uporabljale, bodo to razumeli.
Z namiznimi aplikacijami sem sodeloval več kot 10 let (večinoma Visual Basic 6, Java Swing in Windows Forms), preden sem prvič rokoval na Windows Presentation Foundation (WPF) že leta 2010. V bistvu je bil WPF ustvarjen za nadomesti Windows Forms, ki je prvi .NET-ov okvir za razvoj namizja.
Glavne razlike med WPF in Windows Forms so precejšnje, najpomembnejše pa so:
Ko sem se začel učiti WPF in njegove zmožnosti, mi je bil naravnost všeč! Nisem mogel verjeti, kako enostavno je bil vzorec MVVM implementirati in kako dobro je delovala vezava lastnosti. Nisem si mislil, da bom našel kaj za izboljšanje tega načina dela, dokler nisem naletel na reaktivno programiranje in njegovo uporabo z WPF:
V tej objavi upam, da bom lahko pokazal zelo preprosto izvajanje aplikacije WPF z uporabo reaktivnega programiranja z vzorcem MVVM in dostopal do API-ja REST.
Aplikacija bo lahko:
Zgradili boste odjemalca WPF, ki uporablja storitev RESTful Web API Core 2.
najboljša vadnica za c ++
Stranka:
Strežniška stran:
Kaj boste potrebovali:
Zaledje
Zaženite novo rešitev Visual Studio s spletno aplikacijo ASP.NET Core.
Konfigurirajte ga kot API, saj ga bomo uporabljali le kot zaledje za našo aplikacijo WPF.
kako določiti ceno opcije
Na koncu bi morali dobiti rešitev VS s strukturo, podobno tej:
Zaenkrat imamo vse, kar potrebujemo za zagon našega REST API-ja. Če zaženemo naš projekt, bo naložil spletni brskalnik (tistega, ki smo ga nastavili v Visual Studio), ki kaže na spletno mesto, gostovano v IIS Express, ki bo prikazalo odgovor na klic REST z objektom JSON.
Zdaj bomo za našo storitev REST nastavili JWT Authentication.
Na koncu startup.cs
datoteko, dodajte naslednje vrstice.
static readonly byte[] JwtKey = Encoding.ASCII.GetBytes(@'this is a test key'); private void LoadJwtAuthorization(IServiceCollection services) { services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.Events = new JwtBearerEvents { OnTokenValidated = context => { var userId = int.Parse(context.Principal.Identity.Name); if (userId == 0) { //Handle user validation against DB context.Fail('Unauthorized'); } return Task.CompletedTask; } }; x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(JwtKey), ValidateIssuer = false, ValidateAudience = false }; }); }
Tudi znotraj ConfigureServices
, pokličite metodo, ki smo jo pravkar ustvarili pred AddMvc
metoda se pokliče.
public void ConfigureServices(IServiceCollection services) { LoadJwtAuthorization(services); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
Nazadnje prilagodite Configure
metoda, tako da izgleda takole:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAuthentication(); app.UseMvc(); }
Do zdaj smo vzpostavili JWT Authentication, ki se bo uporabljal na naših krmilnikih, če je ta definirana. Nato bomo prilagodili krmilnik, tako da bo uporabljal preverjanje pristnosti, ki smo ga opisali.
Na ValuesController
bomo dodali AuthorizeAttribute
torej spominja na to:
[Route('api/[controller]')] [ApiController] [Authorize] public class ValuesController : ControllerBase { ... }
Če bomo poskusili zagnati našo storitev, bomo dobili takšno napako 401:
Torej, morali bomo dodati metodo za preverjanje pristnosti naših uporabnikov. Zaradi poenostavitve bomo to storili isto ValuesController
razred.
[AllowAnonymous] [HttpPost('authenticate')] public IActionResult Authenticate([FromBody]JObject userInfo) { var username = userInfo['username'].ToString(); var password = userInfo['password'].ToString(); //We would validate against the DB if (username != 'user' || password != '123') { return BadRequest(new { message = 'Username or password is incorrect' }); } // return basic user info (without password) and token to store on the front-end return Ok(CreateUserToken(1)); } private string CreateUserToken(int userId) { var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, userId.ToString()) }), Expires = DateTime.UtcNow.AddDays(7), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Startup.JwtKey), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); }
Zdaj smo ustvarili metodo z anonimnim dostopom, kar pomeni, da jo bodo lahko vsi odjemalci, tudi tisti, ki niso overjeni, poklicali s sporočilom POST, ki vsebuje objekt JSON, in predali niz za svoje uporabniško ime in niz za svoje geslo.
testno usmerjen razvoj v primerjavi z vedenjskim razvojem
Ko ga pregledamo pri poštarju, dobimo to:
Kot lahko vidimo, je bil rezultat metode overjanja tisti niz, ki ga moramo zdaj uporabiti kot žeton za vsak klic API-ja.
Ko je žeton vključen v glave sporočila, poteka preverjanje veljavnosti in če so posredovani pravilni parametri, storitev zažene metodo in vrne njeno vrednost. Če na primer pokličemo krmilnik vrednosti in prenesemo žeton, dobimo enak rezultat kot prej:
Zdaj bomo ustvarili metodo za določanje zemljepisne širine in dolžine trenutnega avtomobila, ki mu sledimo. Še enkrat, za poenostavitev bo to zgolj preskusna metoda, ki bo najprej vrnila naključno lokacijo in začela premikati avto z določeno razdaljo vsakič, ko bo metoda poklicana.
Najprej prilagodimo Get(int id)
v ValuesController
razred, da bo videti tako:
[HttpGet('{id}')] public ActionResult Get(int id) { var location = LocationHelper.GetCurrentLocation(id); dynamic jsonObject = new JObject(); jsonObject.Latitude = location.latitude; jsonObject.Longitude = location.longitude; return jsonObject.ToString(); }
Nato dodamo novo LocationHelper
razred, ki bo obravnaval sedanjo in prihodnjo lokacijo avtomobilov, ki jim sledimo.
public static class LocationHelper { private static readonly Random Randomizer = new Random(); private const double PositionDelta = 0.0001d; internal static (double latitude, double longitude) GetCurrentLocation(int id) { if (!Locations.ContainsKey(id)) { Locations.Add(id, default((double latitude, double longitude))); } //This method updates the last known location for the car and simulates its movement UpdateLocation(id); return Locations[id]; } private static void UpdateLocation(int id) { (double latitude, double longitude)loc = Locations[id]; //If the default value is found, randomly assign a starting point. if (loc.latitude == default(double) && loc.longitude == default(double)) { loc = Locations[id] = GetRandomStartingPoint(); } if (Randomizer.Next(2) > 0) { //In this scenario we simulate an updated latitude loc.latitude = loc.latitude + PositionDelta; } else { //Simulated longitude change loc.longitude = loc.longitude + PositionDelta; } Locations[id] = loc; } private static (double latitude, double longitude) GetRandomStartingPoint() { //Set inside the continental US return (Randomizer.Next(31, 49), Randomizer.Next(-121, -75)); } private static readonly Dictionary Locations = new Dictionary(); }
To je to za zadnji del.
Sprednji del:
Zdaj bomo ustvarili novo aplikacijo WPF. Ko smo ga ustvarili, bo Visual Studio v našo rešitev dodal nov projekt z naslednjo strukturo.
metode diskontiranih denarnih tokov za proračun kapitala osredotočajo na
Nadzor zemljevidov Bing:
Če želimo uporabiti nadzor WPF za Bing Maps, bomo morali namestiti SDK (naveden zgoraj) in ga dodati kot sklic na našo aplikacijo WPF. Glede na to, kje ste ga namestili, je DLL morda na drugi poti. Namestil sem ga na privzeto mesto in dodal na naslednji način:
Nato bomo dodali nuget pakete za reactiveui
, reactiveui-wpf
in refit
našemu projektu WPF, ki nam bo omogočil, da bomo ustvarili modele pogledov z uporabo reaktivnega programiranja in uživanjem našega API-ja REST.
Zdaj bomo ustvarili svoj ViewModel
. Dodajte nov razred z imenom MainViewModel.cs
in naj bo videti tako:
public class MainViewModel : ReactiveObject { #region Private Members private readonly ITrackingService _service; private readonly ISubject _locationUpdate; #endregion #region Methods public MainViewModel() { _service = Locator.Current.GetService(); _locationUpdate = new Subject(); UpdateCar = ReactiveCommand.Create(() => { var parsedCorrectly = int.TryParse(NewCarToFollow, out int newCar); NewCarToFollow = null; if (!parsedCorrectly) { MessageBox.Show('There was an error reading the number of the car to follow. Please, review it.', 'Car Tracking Service', MessageBoxButton.OK, MessageBoxImage.Warning); return; } FollowedCar = newCar; }, canExecute: this.WhenAnyValue(x => x.NewCarToFollow).Select(x => !string.IsNullOrWhiteSpace(x))); /*This Scheduled method is where we get the location for the car being followed every 500 ms. We call the service with the car id, our JWT Token, and transform the result to a ValueTuple (double latitude, double longitude) to pass to our Subject's OnNext method so it can be received by the view */ Scheduler.Default.SchedulePeriodic(TimeSpan.FromMilliseconds(500), () => _service.GetLocation(FollowedCar, App.GetToken()) .Select(jo => ( latitude: double.Parse(jo['Latitude'].ToString()), longitude: double.Parse(jo['Longitude'].ToString()) )).Subscribe(newLocation => _locationUpdate.OnNext(newLocation))); } #endregion #region Properties private string _newCarToFollow; public string NewCarToFollow { get => _newCarToFollow; set => this.RaiseAndSetIfChanged(ref _newCarToFollow, value); } private int _followedCar = 1; public int FollowedCar { get => _followedCar; set => this.RaiseAndSetIfChanged(ref _followedCar, value); } public IObservable LocationUpdate => _locationUpdate; private ReactiveCommand _updateCar; public ReactiveCommand UpdateCar { get => _updateCar; set => this.RaiseAndSetIfChanged(ref _updateCar, value); } #endregion }
Če želite vedeti, da obstaja ViewModel
pritrjeni nanjo in jo bomo lahko uporabljali, bomo morali spremeniti nekaj MainView.xaml.cs
mapa.
public partial class MainWindow : IViewFor { public MainWindow() { InitializeComponent(); ViewModel = Locator.CurrentMutable.GetService(); /*Our ViewModel exposes an IObservable with a parameter of type ValueTuple (double latitude, double longitude) and it gets called every time the ViewModel updates the car's location from the REST API.*/ ViewModel.LocationUpdate .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(SetLocation); } private void SetLocation((double latitude, double longitude) newLocation) { //New location for the tracked vehicle. var location = new Location(newLocation.latitude, newLocation.longitude); //Remove previous pin myMap.Children.Clear(); //Center pin and keep same Zoom Level myMap.SetView(location, myMap.ZoomLevel); var pin = new Pushpin { Location = location, Background = Brushes.Green }; //Add new pin to the map myMap.Children.Add(pin); } /// /// Allows the ViewModel to be used on the XAML via a dependency property /// public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register('ViewModel', typeof(MainViewModel), typeof(MainWindow), new PropertyMetadata(default(MainViewModel))); /// /// Implementation for the IViewFor interface /// object IViewFor.ViewModel { get => ViewModel; set => ViewModel = (MainViewModel)value; } /// /// Regular property to use the ViewModel from this class /// public MainViewModel ViewModel { get => (MainViewModel)GetValue(ViewModelProperty); set => SetValue(ViewModelProperty, value); } }
Nato bomo spremenili MainWindow.xaml
datoteko, da bo videti tako:
Car to follow
Pomembno je prilagoditi CredentialsProvider
z lastnim ključem Bing Maps.
Da bomo lahko dostopali do našega API-ja REST, bomo uporabili obnovitev. Vse, kar moramo storiti, je ustvariti vmesnik, ki opisuje metode API-jev, ki jih bomo uporabljali. Tako ustvarimo nov vmesnik z imenom ITrackingService z naslednjo vsebino:
public interface ITrackingService { [Post('/api/values/authenticate')] IObservable Authenticate([Body] JObject user); [Get('/api/values/{id}')] IObservable GetLocation(int id, [Header('Authorization')] string authorization); }
Končno spremenimo App
razred za vključitev vbrizgavanja odvisnosti (z uporabo Splata, ki je bil dodan, ko smo vključili sklic na reactiveui
), nastavite ServerUri
(ki bi ga morali spremeniti v vrata, ki jih dobite, ko zaženete REST API) in simulirajte našo prijavo na samem začetku aplikacije.
public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); SetDependencyInjection(); LogIn(); } private void SetDependencyInjection() { Locator.CurrentMutable.RegisterLazySingleton(() => RestService.For(ServerUri), typeof(ITrackingService)); Locator.CurrentMutable.RegisterLazySingleton(() => new MainViewModel(), typeof(MainViewModel)); } private static string Token; private const string ServerUri = 'http://localhost:54587'; private void LogIn() { try { var userInfo = new JObject { ['username'] = 'user', ['password'] = '123' }; Token = Locator.Current.GetService() .Authenticate(userInfo) .Wait(); } catch { MessageBox.Show('There was an error validating the user. Is the service up?'); Shutdown(); } } internal static string GetToken() { return $'Bearer {Token}'; } }
Na koncu, ko zaženemo našo aplikacijo, bomo lahko v realnem času videli simulacijo premikajočega se avtomobila s koordinatami, ki jih vsakih 500 ms vzamemo iz API-ja REST. Uporabnik lahko tudi avtomobil, ki ga spremljate, spremeni na kateri koli drug ID in zanj bo ustvarjen nov nabor podatkov.
Upam, da je ta majhen primer na dostopen način pokazal osnove ravnanja z API-jem REST z reaktivnim programiranjem v WPF.
Iz tega lahko vedno prenesete celoten izvorni projekt odlagališče .
Nekaj področij, na katera lahko nadaljujete s tem primerom, ki vam lahko pomagajo razumeti:
najbolj priljubljena spletna mesta za zmenke 2017
Reaktivno programiranje se lahko izkaže za koristno, če si prizadevamo doseči nadzorovan način uporabe programiranja na podlagi dogodkov, ne da bi pri tem naleteli na običajne težave, povezane s to paradigmo. Uporaba za nove dosežke je tako preprosta kot dodajanje nekaj sklicev na dobro podprte odprtokodne knjižnice. Najpomembneje pa je, da je vključitev v obstoječe zbirke kod lahko progresivna in ne sme prekiniti združljivosti s komponentami, ki je ne izvajajo. Ta članek je obravnaval reaktivno programiranje za WPF, vendar obstajajo vrata do večine glavnih jezikov in okvirov, zaradi česar je reaktivno programiranje dobra pustolovščina za vse razvijalce.
Kot vajo morate:
Spletni žetoni JSON so predmeti JSON, ki so varen način za predstavitev nabora informacij med obema stranema.
JWT je ena izmed najbolj priljubljenih možnosti sodobnih aplikacij za preverjanje pristnosti zaradi svoje varnosti in robustnosti.
Omogočajo enostaven način urejenega in brez večjih stroškov reševanja dogodkov in asinhronega programiranja.
Konstrukcijo novih predmetov lahko definirate v eni sami točki v bazi kode in od takrat naprej lahko domnevate, da bodo vaši predmeti na voljo za uporabo.
Ne. Windows Presentation Foundation je grafični podsistem Microsofta za upodabljanje uporabniških vmesnikov v aplikacijah, ki temeljijo na sistemu Windows.
To je eden od načinov, na katerega lahko oblikujete namizne aplikacije za Windows. V zvezi s tem je lahko mišljena kot alternativa Windows Forms.
WPF je Microsoftov priporočeni način za razvoj novih namiznih aplikacij. Z desetletjem stabilnosti je prilagodljiv nabor orodij, ki se uporabljajo za ustvarjanje čudovitih in sodobnih aplikacij, in omogoča enostavno ločevanje skrbi (videz in občutek vs oblikovanje), kot nobeno drugo za okolje Windows.