Capítol 7: Afegir funcionalitat a l’aplicació
La Kiana i la Maria estan encantades de mostrar l'aplicació d'administració d'inventaris al Caleb, el tècnic de camp. Li agrada, però suggereix afegir alguna funcionalitat addicional a la interfície d'usuari per facilitar-ne l'ús. En concret, Caleb voldria poder:
Afegir una foto del treball fet en una estufa o una unitat d'aire condicionat i afegir-la als detalls de la cita a la pantalla Edita la cita. Aquesta imatge podria ser útil com a comprovant de les reparacions realitzades. La pantalla Edita la cita habilita actualment l'usuari per afegir una imatge a la cita, però la imatge encara no es desa perquè aquesta característica encara no s'ha implementat completament. La raó d'aquesta omissió és que la Kiana i la Preeti han de determinar el millor lloc per emmagatzemar dades d'imatge. En Caleb voldria afegir aquesta funcionalitat al més aviat possible.
Visualitzeu un historial complet de les cites d'un client per fer el seguiment de les reparacions que s'han sol·licitat i supervisar els problemes continuats que podrien obligar els tècnics a fer visites repetidament.
Demaneu les peces des de la pantalla Detalls de la peça.
A més, el control d'imatge a la pantalla Detalls de la peça mostra les imatges emmagatzemades a una adreça URL especificada. Actualment, les adreces URL de les dades són simplement contenidors. Igual que amb les fotografies de la pantalla de cites, la Kiana i la Preeti han de determinar el millor lloc per emmagatzemar les imatges per tal que estiguin disponibles per a l'aplicació.
Afegir una fotografia a una cita
Les fotografies s'han d'emmagatzemar a qualsevol indret accessible per a l'aplicació. Per motius de rendiment i seguretat, la Preeti no vol que es desin a la base de dades SQL de l'Azure o a OneDrive. En lloc d'això, ella i la Kiana decideixen utilitzar l'Emmagatzematge blob de l'Azure. L'Emmagatzematge blob s'ha optimitzat per a objectes binaris grans i és robust, amb seguretat integrada. El Power Apps té un connector que permet l'accés a l'Emmagatzematge blob. La Maria suggereix afegir una nova pantalla sobre la imatge, millorant l'experiència de l'usuari per a en Caleb.
Més informació: Emmagatzematge blob de l'Azure
En Preeti crea el compte d'Emmagatzematge blob des del portal de l'Azure seguint aquests passos:
Al portal de l'Azure, a la pàgina inicial, seleccioneu + Crea un recurs. Al quadre Cerca a Marketplace, introduïu el compte d'emmagatzematge i, a continuació, seleccioneu Retorn.

A la pàgina Compte d'emmagatzematge, seleccioneu Crea.
A la pàgina Crea un compte d'emmagatzematge, introduïu els detalls següents i, a continuació, seleccioneu Revisa + crea:
- Subscripció: seleccioneu la subscripció
- Grup de recursos: webapi_rg
- Nom de compte d'emmagatzematge: proporcioneu un nom únic global i anoteu-lo per a més endavant.
- Ubicació: seleccioneu la ubicació més propera
- Rendiment: Estàndard
- Tipus de compte: BlobStorage
- Replicació: RA-GRS

A la pàgina de validació, seleccioneu Crea i espereu que es proveeixi el compte d'emmagatzematge.
Aneu a la pàgina del compte d'emmagatzematge nou.
A la pàgina Informació general, seleccioneu Contenidors.

A la pàgina Contenidors, seleccioneu + Contenidor. Creeu un contenidor nou anomenat fotos i, a continuació, seleccioneu Crea. Canvieu el Nivell d'accés públic a Blob.

De nou a la pàgina Informació general del compte d'emmagatzematge, a configuració, seleccioneu Tecles d'accés. A la pàgina Tecles d'accés, seleccioneu Mostra les tecles. Anoteu el valor de la clau per a clau1.

La Preeti dona el nom del compte d'emmagatzematge i la clau a la Kiana, que utilitza aquesta informació per crear un connector personalitzat per a l'aplicació seguint aquests passos:
Inicieu la sessió a Power Apps.
A la subfinestra esquerra, expandiu Dades i seleccioneu Contenidors. Cal que enumereu les connexions existents utilitzades per l'aplicació. Seleccioneu + Connexió nova.

A la pàgina Connexió nova, desplaceu-vos cap avall, seleccioneu Connexions, seleccioneu Emmagatzematge blob de l'Azure i, a continuació, seleccioneu Crea.

Al quadre de diàleg Emmagatzematge blob de l'Azure, introduïu el nom del compte d'emmagatzematge i la clau d'accés que ha proporcionat la Preeti i, a continuació, seleccioneu Crea.

Espereu mentre es crea la connexió nova. Hauria d'aparèixer a la llista de connexions.
La Maria pot utilitzar aquesta connexió a l'Emmagatzematge blob a l'aplicació per desar i recuperar imatges fotogràfiques. La seva primera tasca és afegir la connexió a l'aplicació seguint aquests passos:
Obriu l'aplicació VanArsdelApp per editar-la al Power Apps Studio.
A la subfinestra Dades, seleccioneu Afegeix dades, cerqueu el connector d'Emmagatzematge blob de l'Azure i, a continuació, seleccioneu el connector.

Al quadre de diàleg Emmagatzematge blob de l'Azure, seleccioneu el connector d'Emmagatzematge blob de l'Azure per afegir-lo a l'aplicació.

La següent tasca de Ia Maria és afegir una pantalla que permeti a un tècnic o un enginyer desar una fotografia. La Maria decideix afegir una pantalla nova amb el control d'imatge. Quan l'aplicació s'executa en un dispositiu mòbil, aquest control es pot integrar amb la càmera per permetre que el tècnic faci una foto. En altres dispositius, aquest control sol·licita a l'usuari que carregui un fitxer d'imatge. Afegeix un enllaç a aquesta pantalla nova des de la pantalla EditAppointment seguint aquests passos:
Al menú Insereix, seleccioneu Nova pantalla i, a continuació, seleccioneu la plantilla amb desplaçament.

A la subfinestra Visualització en arbre, seleccioneu la pantalla nova i canvieu el nom per TakePhoto.
Canvieu la propietat Text del control LblAppNameX en aquesta pantalla per Take a photograph.
Suprimiu el control CanvasX de la pantalla.
Al menú Insereix, a la llista desplegable Mitjans, seleccioneu Afegeix una imatge per crear un control d'imatge nou.

Nota
El control d'imatge és en realitat un component personalitzat compost que permet a l'usuari afegir una imatge a la pantalla i visualitzar-ne els resultats.
Canviar la mida i reubicar el control d'imatge per ocupar el cos de la pantalla.
A la subfinestra Visualització en arbre, seleccioneu el control IconBackarrowX a la pantalla AppointmentDetails i, a continuació, seleccioneu Copia.

Al menú de visualització en arbre, feu clic amb el botó dret a la pantalla TakePhoto i, a continuació, seleccioneu Enganxa. El control IconBackArrowX s'afegirà a la pantalla.

Desplaceu el control IconBackArrowX a la part superior esquerra de la barra de capçalera.
A la subfinestra Visualització en arbre, seleccioneu el control IconBackarrowX a la pantalla TakePhoto. A la subfinestra dreta, a la pestanya Opcions avançades, modifiqueu la propietat de l'acció onSelect per Navigate(EditAppointment, ScreenTransition.None).
Afegiu un nou control d'icona Desa a la part superior dreta de la barra de capçalera. Definiu la propietat Visible d'aquest control com a If(IsBlank(AddMediaButton1.Media), false, true).
Aquesta opció fa que la icona Desa sigui invisible si l'usuari no ha seleccionat cap imatge.

Canvieu la fórmula de la propietat d'acció onSelect del control d'icona Desa per la següent.
Set(ImageID, GUID() & ".jpg"); AzureBlobStorage.CreateFile("photos", ImageID, AddMediaButton1.Media); Patch(appointmentsCollection, LookUp(appointmentsCollection,id=BrowseAppointmentsGallery.Selected.id), {imageUrl:"https://myappphotos.blob.core.windows.net/photos/" & ImageID}); Navigate(EditAppointment,ScreenTransition.Cover);Substituïu <storage account name> amb el nom del compte d'emmagatzematge de l'Azure que ha creat la Preeti.
Aquest codi puja la imatge al contenidor de fotos de l'Emmagatzematge blob. Cada imatge s'atorga un nom de fitxer únic. La funció Pedaç actualitza la propietat ImageUrl al registre de cites amb l'adreça URL de la imatge a l'Emmagatzematge blob.
A la subfinestra Visualització en arbre, expandiu el control AddMediaWithImageX. Modifiqueu la propietat Imatge del control UploadedImageX i definiu-la com a AppointmentImage.
AppointmentImage és una variable que s'emplenarà amb una imatge carregada per l'usuari o com a resultat de fer una foto. Podreu inicialitzar aquesta variable a la pantalla EditAppointment més endavant.
A la subfinestra Visualització en arbre, seleccioneu el control AddMediaButtonX. Definiu la propietat UseMobileCamera d'aquest control en cert. Definiu la propietat d'acció OnChange del control en el següent.
Set(AppointmentImage, AddMediaButton1.Media)Aquesta fórmula canvia la variable AppointmentImage per fer referència a la imatge nova. El control UploadedImageX mostrarà aquesta imatge.
A la subfinestra Visualització d'arbre, seleccioneu la pantalla EditAppointment.
Expandiu el control EditFormX. Sota el control Image_DataCardX, suprimiu el control AddPictureX.

Seleccioneu el control ImageX. Canvieu les propietats següents:
- Imatge: Parent.Default
- X: 30
- Y: DataCardKey X.Y + DataCardKey X.Height + 150 (where DataCardKeyX és la targeta de dades que conté el control ImageX)
- Width: Parent.Width - 60
- Height: 400
Nota
El control d'imatge s'arrossegarà per sota de la part inferior de la pantalla, però s'afegirà automàticament una barra de desplaçament per permetre la visualització de la imatge.
Afegiu una icona de Camera a la targeta de dades i col·loqueu-la entre l'etiqueta Image i el control ImageX. Canvia el nom del control per CameraIcon.
Nota
Assegureu-vos de seleccionar el control d'icona de càmera, no el control multimèdia de la càmera.

Definiu la propietat d'acció OnSelect del control CameraIcon en el següent.
Set(AppointmentImage, SampleImage); Navigate(TakePhoto, ScreenTransition.None);Quan l'usuari seleccioni aquesta icona, anirà a la pantalla TakePhoto, on podrà fer una foto o carregar una imatge. La imatge inicial que es visualitza serà la imatge d'exemple per defecte.
Per provar l'aplicació, feu el següent:
A la subfinestra Visualització d'arbre, seleccioneu la pantalla Inici.
Seleccioneu F5 per obtenir una visualització prèvia de l'aplicació.
A la pantalla d'inici, seleccioneu Cites.
A la pantalla de navegació, seleccioneu qualsevol cita.
A la pantalla de detalls de la cita, seleccioneu la icona d'edició de la capçalera de pantalla.
A la pantalla d'edició, seleccioneu la icona Càmera de la imatge.
Verifiqueu que apareix la pantalla Fer una foto.
Seleccioneu Canvia la foto i carregueu la foto que voleu (o feu una foto, si executeu l'aplicació en un dispositiu mòbil).
Seleccioneu Desa. Verifiqueu que la imatge aparegui a la pàgina de detalls i, a continuació, seleccioneu la icona de marca de verificació per desar els canvis a la base de dades.
Tanqueu la finestra de visualització prèvia i torneu al Power Apps Studio.
Visualitzar imatges de peces
Havent determinat que l'Emmagatzematge blob és una ubicació ideal per desar imatges associades amb cites, la Preeti i la Kiana decideixen que han d'utilitzar el mateix mètode per emmagatzemar les imatges de les peces. Un avantatge clau d'aquest mètode és que no requereix modificacions a l'aplicació. L'aplicació reutilitza el mateix compte d'emmagatzematge i la mateixa connexió. Com a exercici de migració diferent, poden fer les accions següents:
Crear un contenidor d'Emmagatzematge blob nou.
Carregar les imatges de peces a aquest contenidor.
Canviar les referències ImageUrl a la taula Peces de la base de dades InventoryDB a l'adreça URL de cada imatge.
L'aplicació recollirà automàticament l'adreça URL nova de cada imatge de peça i el control Imatge a la pantalla PartDetails mostrarà la imatge.
Fer el seguiment de l'historial de cites d'un client
La Maria pensa que es podria afegir la possibilitat de visualitzar ràpidament tot l'historial de les visites de tècnics anteriors d'un client a l'aplicació creant un component personalitzat. Parlant amb en Caleb sobre la informació que volen veure, la Maria fa un esborrany d'un disseny senzill que comprèn les notes i la data de cada visita.

Pel que fa a les dades, la Maria considera que un control de la galeria és la millor manera de visualitzar les dades de la taula en una pantalla.
La Maria crea el component personalitzat d'aquesta manera:
Amb el Power Apps Studio, a la subfinestra Visualització d'arbre, seleccioneu Components i, a continuació, seleccioneu + Component nou.

Es crea un component en blanc nou anomenat Component1. Canvieu el nom del component per DateHistoryComponent.

Al menú Insereix, seleccioneu Galeria i, a continuació, trieu la plantilla de la galeria Alçada flexible en blanc.

Desplaceu el control de la galeria i torneu a canviar la mida per emplenar el component personalitzat.
Seleccioneu l'element Afegeix un element de la subfinestra d'inserció i, a continuació, seleccioneu Etiqueta de text.

A la subfinestra visualització en arbre, canvieu el nom del control d'etiqueta per NotesLabel. Definiu la propietat Overflow en Overflow.Scroll. Aquesta opció permet al control visualitzar diverses línies de text i permet a l'usuari desplaçar-se per ell. Definiu les propietats següents per tal de posicionar i canviar la mida del control:
- LineHeight: 2
- X: 28
- Y: 18
- Width: 574
- Height: 140
Afegiu una segona etiqueta de text al control. Canvieu el nom d'aquest control per DateLabel i definiu les propietats següents:
- LineHeight: 2
- X: 28
- Y: 174
- Width: 574
- Height: 70
Per veure com es veurà el control quan s'insereixi a l'aplicació i es visualitzi amb el seu tema, a la subfinestra Visualització d'arbre, seleccioneu DateHistoryComponent. A la subfinestra dreta, a la pestanya Avançat, seleccioneu el camp Emplena i canvieu el color per RGBA(0, 0, 0, 1).

A la subfinestra Insereix, expandiu Formes i afegiu un control Rectangle al component personalitzat. Definiu les propietats següents per a aquest control:
- X: 0
- Y: 273
- Width: Parent.Width
- Height: 2
Aquest control actua com a separador entre els registres que es visualitzen a la galeria.

La Maria està familiaritzada amb l'addició de controls a les pantalles i la creació d'aplicacions amb el Power Apps. Tanmateix, els components reutilitzables no funcionen de la mateixa manera. La Kiana ha descrit a la Maria que, per poder utilitzar les dades en un component personalitzat, ha d'afegir algunes propietats d'entrada personalitzada addicionals. La Kiana també ha explicat a la Maria que ha de proporcionar dades d'exemple per a aquestes propietats, per poder fer referència als camps de dades dels controls del seu component, de la següent manera:
A la subfinestra Visualització d'arbre, seleccioneu DateHistoryComponent. A la subfinestra dreta, a la pestanya Propietats, seleccioneu Nova propietat personalitzada.

Al quadre de diàleg Nova propietat personalitzada, especifiqueu els valors següents i, a continuació, seleccioneu Crea:
- Nom de visualització: Dades
- Nom: Dades
- Descripció: La taula de cites d'un client, on es mostren les notes i les dates
- Tipus de propietat: Entrada
- Tipus de dades: Taula
- Augmenta el valor onReset quan canviï el valor: Deixa en blanc

Per canviar les dades d'exemple visualitzades pel control, seleccioneu la propietat personalitzada de dades nova. Al camp de fórmula, introduïu Table({Notes: "Example notes field text.", 'Appointment Date': Text(Today())}).

A la subfinestra Visualització en arbre, seleccioneu el control GaleriaX a DateHistoryComponent i canvieu el nom per Cita.
A la subfinestra dreta, a la pestanya Opcions avançades, definiu la propietat Elements del control de la galeria AppointmentHistory en Parents.Data.

Seleccioneu el control NotesLabel. A la subfinestra dreta de la pestanya Avançat, canvieu la propietat Text per ThisItem.Notes i canvieu la propietat Mida per 20.
Nota
La propietat Mida especifica el cos de lletra del text que visualitza el control.
Seleccioneu el control DateLabel per canviar la propietat Text per ThisItem.'Appointment Date' i canvieu la propietat Mida per 20. Els camps del component personalitzat han de mostrar les dades d'exemple.

El component personalitzat s'ha completat. La Maria crea una pantalla nova per mostrar l'historial de cites d'un client mitjançant aquest component, de la següent manera:
A la subfinestra Visualització d'arbre, seleccioneu la pestanya Pantalles.
Expandiu la pantalla BrowseAppointments, expandiu el control BrowseAppointmentsGallery i seleccioneu el control Cos_1. Al menú Insereix, seleccioneu Icones i, a continuació, seleccioneu la icona Llista detallada.

Canvieu el nom del control d'icona per ViewAppointments.
Al menú Visualització en arbre, seleccioneu el control BrowseAppointmentsGallery. A la subfinestra dreta, a la pestanya Avançat, canvieu la propietat TemplateSize per 220. Si augmenteu aquesta propietat, s'expandeix l'espai disponible a la galeria.
Desplaceu la icona ViewAppointments a l'espai buit sota el nom del client.

Seleccioneu el control d'icona ViewAppointments. Definiu la propietat d'acció OnSelect a la fórmula següent.
ClearCollect(customerAppointmentsCollection, FieldEngineerAPI.getapicustomeridappointments(ThisItem.customerId)); Navigate(AppointmentsHistoryScreen, ScreenTransition.Fade)Aquesta fórmula emplena una col·lecció anomenada customerAppointmentsCollection amb les cites per al client seleccionat i, a continuació, es desplaça a AppointmentHistoryScreen per mostrar-les. Aquesta pantalla es crearà en els passos següents.
Al menú Insereix, seleccioneu Nova pantalla i, a continuació, seleccioneu la plantilla amb desplaçament.

Canvieu el nom de la pantalla nova per AppointmentHistoryScreen.
Suprimiu el control LlençX que s'ha afegit a aquesta pantalla.

Seleccioneu el control LblAppNameX en aquesta pantalla. A la subfinestra dreta, a la pestanya Avançat, canvieu la propietat Text pel següent.
"Appointments History for " & BrowseAppointmentsGallery.Selected.customer.nameDefiniu les propietats següents per al control LblAppNameX per ajustar la posició i la mida:
- X: 90
- Y: 0
- Width: 550
- Height: 140
Seleccioneu el control RectQuickActionBarX i definiu la propietat Alçada en 140.
Afegiu un control d'icona esquerra a la capçalera de pantalla, a l'esquerra del títol. Definiu la propietat d'acció onSelect per a aquest control en Navigate(BrowseAppointments, Transition.None).

Al menú Insereix, seleccioneu Personalitzat i, a continuació, seleccioneu la icona DateHistoryComponent.

Desplaceu i canvieu la mida del component de manera que ocupi el cos de la pantalla, sota la capçalera.

Definiu les propietats següents per a aquest component:
- Dades: customerAppointmentsCollection
- Data de la cita: startDateTime
- Notes: notes
Desa l'aplicació.
Per provar l'aplicació, feu el següent:
A la subfinestra Visualització d'arbre, seleccioneu la pantalla Inici.
Seleccioneu F5 per obtenir una visualització prèvia de l'aplicació.
A la pantalla d'inici, seleccioneu Cites.
A la pantalla de navegació, seleccioneu la icona de la llista de detalls per a qualsevol cita.
Verifiqueu que es mostra la pantalla Historial de cites del client seleccionat.
Tanqueu la finestra de visualització prèvia i torneu al Power Apps Studio.
Demanar peces
Un requisit clau del sistema és permetre a un tècnic demanar les peces necessàries quan visita un client. Si les peces estan en estoc, hauria de ser possible planificar una altra visita per completar la reparació en la propera data convenient per al client. Si les peces estan actualment fora d'estoc i s'han de demanar, el tècnic pot dir-ho al client. D'aquesta manera, en Malik pot organitzar una cita amb el client quan la Maria rebi l'avís que les peces ja són al magatzem.
A la base de dades que es mostra a la imatge següent, la part corresponent a les reserves utilitza les taules de la base de dades InventoryDB. La taula Comandes conté informació sobre les comandes de peces fetes. A la taula Reserves s'enumera la llista de les sol·licituds de disponibilitat que han fet els tècnics i enginyers per a les peces. La taula Enginyers proporciona el nom i el número de contacte de l'enginyer que ha fet la consulta, la qual cosa facilita a la Maria, l'administradora de l'inventari, consultar-los si cal.

Per admetre aquesta característica, la Kiana ha d'actualitzar l'API web amb un mètode que cerca el nombre d'elements reservats d'una peça especificada, de la següent manera:
Obriu el projecte API web de FieldEnginerApi al Visual Studio Code.
Afegiu un fitxer anomenat Order.cs a la carpeta Models. Afegiur el codi següent a aquest fitxer. La classe Comandes fa un seguiment dels detalls de les comandes fetes per a les peces.
using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace FieldEngineerApi.Models { public class Order { [Key] public long Id { get; set; } public long BoilerPartId { get; set; } public BoilerPart BoilerPart { get; set; } public long Quantity { get; set; } [Column(TypeName = "money")] public decimal TotalPrice { get; set; } [Display(Name = "OrderedDate")] [DataType(DataType.DateTime)] [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] public DateTime OrderedDateTime { get; set; } public bool Delivered { get; set; } [Display(Name = "DeliveredDate")] [DataType(DataType.DateTime)] [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] public DateTime? DeliveredDateTime { get; set; } } }Afegiu un altre fitxer nou anomenat Reservation.cs la carpeta Models i afegiu el codi següent a aquest fitxer. La classe Reserva inclou informació sobre el nombre d'elements d'una peça determinada que hi ha reservats actualment per a altres clients.
using System; using System.ComponentModel.DataAnnotations; namespace FieldEngineerApi.Models { public class Reservation { [Key] public long Id { get; set; } public long BoilerPartId { get; set; } public BoilerPart BoilerPart { get; set; } public int NumberToReserve { get; set; } public string EngineerId { get; set; } public InventoryEngineer Engineer { get; set; } } }Afegiu un fitxer més, anomenat InventoryEngineer.cs a la carpeta Models, amb el codi següent. La classe InventoryEngineer registra quins enginyers han fet les reserves.
using System.ComponentModel.DataAnnotations; using System.Collections.Generic; namespace FieldEngineerApi.Models { public class InventoryEngineer { [Key] public string Id { get; set; } [Required] public string Name { get; set; } public string ContactNumber { get; set; } public List<Reservation> Reservations { get; set; } } }Obriu el fitxer InventoryContext.cs de la carpeta Models i afegiu les declaracions següents a la classe InventoryContext.
public class InventoryContext : DbContext { public InventoryContext(DbContextOptions\<InventoryContext\> options) : base(options) { } public DbSet<BoilerPart> BoilerParts { get; set; } public DbSet<InventoryEngineer> Engineers { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<Reservation> Reservations { get; set; } }A la finestra Terminal del Visual Studio Code, executeu les ordres següents per crear controladors per a la gestió de comandes i reserves.
dotnet aspnet-codegenerator controller ^ -name OrdersController -async -api ^ -m Order ^ -dc InventoryContext -outDir Controllers dotnet aspnet-codegenerator controller ^ -name ReservationsController -async -api ^ -m Reservation ^ -dc InventoryContext -outDir ControllersObriu el fitxer BoilerPartController.cs de la carpeta Controladors i afegiu el mètode GetTotalReservations següent a la classe BoilerPartsController.
public class BoilerPartsController : ControllerBase { private readonly InventoryContext _context; public BoilerPartsController(InventoryContext context) { _context = context; } ... // GET: api/BoilerParts/5/Reserved [HttpGet("{id}/Reserved")] public async Task<ActionResult<object>> GetTotalReservations(long id) { var reservations = await _context .Reservations .Where(r => r.BoilerPartId == id) .ToListAsync(); int totalReservations = 0; foreach(Reservation reservation in reservations) { totalReservations += reservation.NumberToReserve; } return new {id, totalReservations}; } ... }Editeu el fitxer OrdersController.cs i modifiqueu el mètode PostOrder a la classe OrdersController com es mostra a continuació.
[HttpPost] public async Task<ActionResult<Order>> PostOrder(long boilerPartId, int quantity) { var part = await _context.BoilerParts.FindAsync(boilerPartId); Order order = new Order { BoilerPartId = boilerPartId, Quantity = quantity, OrderedDateTime = DateTime.Now, TotalPrice = quantity * part.Price }; _context.Orders.Add(order); await _context.SaveChangesAsync(); return CreatedAtAction("GetOrder", new { id = order.Id }, order); }Editeu el fitxer ReservationsController.cs. Modifiqueu el mètode PostReservation a la classe ReservationsController, de la següent manera.
[HttpPost] public async Task<ActionResult<Reservation>> PostReservation(long boilerPartId, string engineerId, int quantityToReserve) { Reservation reservation = new Reservation { BoilerPartId = boilerPartId, EngineerId = engineerId, NumberToReserve = quantityToReserve }; _context.Reservations.Add(reservation); await _context.SaveChangesAsync(); return CreatedAtAction("GetReservation", new { id = reservation.Id }, reservation); }A la finestra Terminal, executeu les ordres següents per crear i publicar l'API web preparada per a la implementació.
dotnet build dotnet publish -c Release -o ./publishAl Visual Studio Code, feu clic amb el botó dret a la carpeta de publicació i, a continuació, seleccioneu Implementa a l'aplicació web.
La Preeti pot actualitzar ara el servei d'administració de l'API utilitzat per l'aplicació VanArsdel per reflectir l'API web actualitzat. Això és un canvi no disruptiu; les operacions existents continuaran funcionant, la diferència són els nous controladors i operacions per fer reserves i realitzar comandes. La Preeti realitza les tasques següents:
Nota
La Preeti podria haver triat suprimir l'API d'Enginyers de camp existent i substituir-la per una nova versió, però aquest enfocament podria alterar les aplicacions existents que utilitzen l'API actualment. És una millor pràctica deixar l'API existent com està i afegir-hi les modificacions com a revisió.
Al portal de l'Azure, aneu al Servei d'administració de l'API.
A la pàgina Servei d'administració de l'API, a la subfinestra esquerra, a API, seleccioneu les API.
Seleccioneu l'API d'enginyer de camp, seleccioneu el menú dels tres punts i, a continuació, seleccioneu Afegeix revisió.

Al quadre de diàleg Crea una nova revisió de l'API d'Enginyers de camp, introduïu la descripció Operació GET afegida i operacions POST per a les revisions i comandes i, a continuació, seleccioneu Crea.

A la pàgina REVISION 2, seleccioneu Disseny.

A la pàgina Disseny, seleccioneu Afegeix operació. A la subfinestra FrontEnd, definiu les propietats següents i, a continuació, seleccioneu Desa. Aquesta operació s'utilitza per recuperar el nombre d'elements reservats per a una peça d'estufa determinada:
- Nom de visualització: api/BoilerParts/{id}/Reserved
- Nom: api-boilerparts-id-reserved
- URL: GET api/BoilerParts/{id}/Reserved

A la pestanya Prova per a la nova operació, definiu el paràmetre d'identificador com a número de peça vàlid (l'exemple de la imatge utilitza la peça 1) i, a continuació, seleccioneu Envia.

Verifiqueu que la prova s'hagi completat correctament. L'operació s'ha de completar amb una resposta HTTP 200, i un cos que mostra el nombre de reserves per al producte.

A la pàgina Disseny, seleccioneu Afegeix operació. A la subfinestra FrontEnd, definiu les propietats següents (aquesta operació defineix sol·licituds POST per crear comandes noves):
- Nom de visualització: api/Comandes - POST
- Nom: api-orders-post
- URL: POST api/Orders
A la pestanya Consulta, seleccioneu + Afegeix un paràmetre, afegiu els paràmetres següents i, a continuació, seleccioneu Desa:
- Nom: boilerPartId, Descripció : ID de peça d'estufa, Tipus: llarg
- Nom: quantitat, Descripció : Quantitat, Tipus: enter

Torneu a seleccionar Afegeix una operació a la subfinestra FrontEnd i definiu les propietats següents (aquesta operació defineix sol·licituds POST per crear reserves noves):
- Nom de visualització: api/Reserves - POST
- Nom: api-reservations-post
- URL: POST api/Reservations
A la pestanya Consulta, afegiu els paràmetres següents i, a continuació, seleccioneu Desa:
- Nom: boilerPartId, Descripció: ID de peça d'estufa, Tipus: llarg
- Nom: engineerId, Descripció: Engineer ID, Tipus: cadena
- Nom: quantityToReserve, Descripció: Quantitat per reserva, Tipus: enter
A la pestanya Revisions, seleccioneu la versió nova. Al menú dels tres punts d'aquesta versió, seleccioneu Converteix en l'actual.

Al quadre de diàleg Converteix en la revisió actual, seleccioneu Desa.
Obriu una altra pàgina del navegador web i aneu a l'adreça URL https://<APIM name>.azure-api.net/api/boilerparts/1/reserved on <APIM name> és el nom del servei de l'API. Verifiqueu que obteniu una resposta semblant a la següent.
{"id":1,"totalReservations":5}
L'API web actualitzada ja està disponible. En teoria, la Kiana podria crear un connector personalitzat nou per a l'API web actualitzada i afegir-lo a l'aplicació. A continuació, l'aplicació podria implementar la seva pròpia lògica per determinar quants elements del producte especificat estan en estoc, quants estan reservats, comparar els resultats amb el nombre d'elements necessaris, fer una comanda per a més estocs si cal o reservar elements dels estocs existents. Tanmateix, aquest tipus de lògica s'implementa millor en una aplicació lògica de l'Azure. El Power Apps pot cridar l'aplicació lògica a través d'un connector personalitzat quan un tècnic vol reservar o demanar una peça.
Per crear l'aplicació lògica, la Kiana utilitza els passos següents:
Nota
Per fer més senzilles les coses, l'aplicació lògica creada en aquest exemple és no transaccional. És possible que, entre comprovar la disponibilitat d'una peça i fer una reserva, un usuari simultani pugui crear una reserva en conflicte. Podeu implementar la semàntica transaccional tornant a substituir algunes de les lògiques d'aquesta aplicació lògica amb un procediment emmagatzemat a la base de dades InventoryDB.
Al portal de l'Azure, a la pàgina inicial, seleccioneu + Crea un recurs.
Al quadre Cerca a Marketplace, introduïu Aplicació lògica i, a continuació, seleccioneu Retorn.
A la pàgina Aplicació lògica, seleccioneu Crea.

A la pàgina Crea una aplicació lògica, introduïu els valors següents i, a continuació, seleccioneu Revisa + crea:
- Subscripció: seleccioneu la subscripció de l'Azure
- Grup de recursos: webapi_rg
- Nom de l'aplicació lògica: FieldEnginyerPartsOrdering
- Regió: seleccioneu la mateixa ubicació que heu utilitzat per a l'API web
- Associar amb l'entorn de servei d'integració: Deixeu en blanc
- Habilita les anàlisis de registres: deixa en blanc
A la pàgina de verificació, seleccioneu Crea i espereu mentre es desplega l'aplicació lògica.
Quan s'ha completat la implementació, seleccioneu Anar al recurs.
A la pàgina Dissenyador d'aplicacions lògiques, desplaceu-vos cap avall a la secció Plantilles i, a continuació, seleccioneu Aplicació de lògica en blanc.

A la pestanya Tot, al quadre de text Cerca connectors i disparadors, seleccioneu Sol·licita.

A la pestanya Disparadors, seleccioneu Quan es rebi una sol·licitud HTTP.

Al quadre Esquema JSON del cos de sol·licitud, introduïu l'esquema següent i seleccioneu + Pas nou.
{ "type": "object", "properties": { "boilerPartId": { "type": "integer" }, "numberToReserve": { "type": "integer" }, "engineerId": { "type": "string" } } }
Aquesta esquema defineix el contingut de la sol·licitud HTTP que està esperant l'aplicació lògica. El cos de la sol·licitud comprèn l'identificador d'una peça d'estufa, el nombre d'elements que s'han reservat i l'identificador de l'enginyer que fa la sol·licitud. L'aplicació enviarà aquesta sol·licitud quan un enginyer vulgui reservar una peça.
Al quadre Trieu una operació, seleccioneu Tot i, a continuació, seleccioneu HTTP.

L'aplicació lògica crida l'operació BoilerParts{id} de l'API web per recuperar informació sobre l'element d'estufa proporcionat per la sol·licitud des de l'aplicació.
A la subfinestra Accions, seleccioneu l'acció HTTP.

Al quadre d'acció HTTP, al menú dels punts suspensius, seleccioneu Canvia el nom i canvieu el nom de l'acció per CheckBoilerPart.

Definiu les propietats de l'acció HTTP de la següent manera i, a continuació, seleccioneu + Pas nou:
- Mètode: GET
- URI: https://<APIM name>.azure-api.net/api/boilerparts/, on <APIM name>_ és el nom del vostre servei d'Administració d'API. Al quadre _ Contingut dinàmic per a aquest URI, a la pestanya Contingut dinàmic, seleccioneu boilerPartId

Al quadre Trieu una operació, al quadre Cerca connectors i accions, introduïu Parse JSON i, a continuació, seleccioneu l'acció Parse JSON.

Mitjançant el menú dels punts suspensius per a l'acció Parse JSON, canvieu el nom de l'acció per ParseBoilerPart.
Al quadre Contingut de l'acció ParseReilerPart, al quadre Contingut dinàmic, seleccioneu Cos. Al quadre Esquema, introduïu l'esquema JSON següent i seleccioneu + Pas nou.
{ "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "categoryId": { "type": "string" }, "price": { "type": "number" }, "overview": { "type": "string" }, "numberInStock": { "type": "integer" }, "imageUrl": { "type": "string" }, } }
Aquesta acció analitzarà el missatge de resposta retornat per la sol·licitud getBoilerParts/{id}. La resposta conté els detalls de la peça d'estufa, incloent-hi el nombre que hi ha actualment en estoc.
Al quadre Trieu una operació per al pas nou, seleccioneu el connector HTTP.
A la pestanya Accions, seleccioneu l'acció HTTP.
Mitjançant el menú dels punts suspensius per a l'operació, canvieu el nom de l'operació per CheckReservations.
Definiu les propietats següents per a aquesta operació i, a continuació, seleccioneu + Pas nou:
- Mètode: GET
- URI: https://<APIM name>.azure-api.net/api/boilerparts/. Com abans, al quadre Contingut dinàmic d'aquest URI, a la pestanya Contingut dinàmic, seleccioneu boilerPartId. Al camp URI, annexeu el text /reserved després del contenidor boilerPartId

Al quadre Trieu una operació per a la nova acció, al quadre Cerca connectors i accions, introduïu Parse JSON i, a continuació, seleccioneu l'acció Parse JSON.
Canvieu el nom de l'operació per ParseReservations.
Definiu la propietat Contingut en Cos.
Introduïu l'esquema següent i seleccioneu + Pas nou.
{ "type": "object", "properties": { "id": { "type": "integer" }, "totalReservations": { "type": "integer" } } }
Al quadre Trieu una operació per a la nova acció, al quadre Cerca connectors i accions, introduïu Condició i, a continuació, seleccioneu l'acció Control de condició.

Canvieu el nom de l'operació per CompareStock.
Seleccioneu el quadre Trieu un valor. Al quadre Afegeix contingut dinàmic, a la pestanya Expressió, introduïu l'expressió següent i, a continuació, seleccioneu D'acord.
add(body('ParseReservations')?['totalReservations'], triggerBody()?['numberToReserve'])Aquesta expressió calcula la suma del nombre d'elements de la peça d'estufa especificada que hi ha actualment reservada i el nombre sol·licitat per l'enginyer.

Al quadre de llista desplegable de condició, seleccioneu és superior a.
A la resta, al quadre Trieu un valor, al quadre Contingut dinàmic, a la pestanya Contingut dinàmic, a ParseBoilerPart, seleccioneu numberInStock.

Si el nombre d'unitats necessàries més el nombre reservat és superior al nombre en estoc, l'aplicació ha de fer una comanda per substituir l'inventari. A la branca Cert de l'acció CompareStock, seleccioneu Afegeix una acció.
A la pestanya Tot per a l'operació nova, seleccioneu HTTP i, a continuació, seleccioneu l'acció HTTP.
Canvieu el nom de l'operació per PostOrder.
Definiu les propietats següents per a l'operació PostOrder:
- Mètode: POST
- URI: https://<APIM name>.azure-api.net/api/orders
- A la taula Consultes, a la primera fila, introduïu la clau boilerPartId. Per al valor del quadre Afegeix contingut dinàmic de la pestanya Contingut dinàmic, seleccioneu boilerPartId.
- A la segona fila de la taula Consultes, introduïu la clau quantity. Al camp de valor, introduïu 50.

L'aplicació lògica demanarà automàticament 50 unitats de la peça especificada quan hi hagi pocs estocs.
Nota
L'aplicació lògica assumeix que l'enginyer no intentarà reservar més de 50 unitats d'una peça especificada en una sola sol·licitud.
Deixeu en blanc la branca False de l'acció CompareStock.
Per sota de l'acció CompareStock, seleccioneu + Pas nou.
A la pestanya Tot per a l'operació nova, seleccioneu HTTP i, a continuació, seleccioneu l'acció HTTP.
Canvieu el nom de l'operació per PostReservation.
Definiu les propietats següents per a l'operació PostReservation:
- Mètode: POST
- URI: https://<APIM name>.azure-api.net/api/reservations
- A la taula Consultes, a la primera fila, introduïu la clau boilerPartId. Per al valor del quadre Afegeix contingut dinàmic de la pestanya Contingut dinàmic, seleccioneu boilerPartId.
- A la segona fila, introduïu la clau engineerId. Per al valor del quadre Afegeix contingut dinàmic de la pestanya Contingut dinàmic, seleccioneu engineerId.
- A la tercera fila, introduïu la clau quantityToReserve. Per al valor del quadre Afegeix contingut dinàmic de la pestanya Contingut dinàmic, seleccioneu numberToReserve.
Seleccioneu + Pas nou. Al quadre Trieu una operació, cerqueu i seleccioneu l'acció Resposta.
Definiu les propietats següents per a l'acció Resposta:
- Codi d'estat: 200
- Capçaleres: Key - content-type, Value - application/json
- Cos: Al quadre Contingut dinàmic, seleccioneu l'element Cos a la sol·licitud PostReservation. Aquest és el cos que es torna quan es fa la reserva.

A la part superior esquerra de la pàgina Dissenyador d'aplicacions lògiques, seleccioneu Desa. Comproveu que l'aplicació lògica es pugui desar sense errors.
Per crear el connector personalitzat que el Power Apps pot utilitzar per activar l'aplicació lògica, la Kiana duu a terme els passos següents mentre encara es treballa al portal de l'Azure:
A la pàgina Informació general per a l'aplicació lògica, seleccioneu Exporta.

A la subfinestra Exporta al Power Apps, anomeneu el connector PartsOrderingConnector, seleccioneu l'entorn del Power Apps i, a continuació, seleccioneu D'acord.

Inicieu la sessió a Power Apps.
A l'entorn, a Dades, seleccioneu Connectors personalitzats i verifiqueu que PartsOrderingConnector és a la llista.

La Maria pot modificar l'aplicació VanArsdel perquè un tècnic pugui demanar les peces mentre va a un local del client. Afegeix un botó Comanda a la pantalla PartDetails, de la següent manera:
Inicieu la sessió al Power Apps (si encara no ho heu fet).
A Aplicacions, seleccioneu l'aplicació VanArsdelApp. Al menú dels punts suspensius de l'aplicació, seleccioneu Edita.
A la subfinestra Dades, seleccioneu Afegeix dades, cerqueu el connector PartsOrderingConnector i afegiu una connexió nova mitjançant aquest connector.

A la subfinestra Visualització en arbre, expandiu la pantalla PartDetails i després expandiu el formulari DetailForm1.
A la subfinestra de propietats que hi ha a la dreta, seleccioneu Edita els camps. A la subfinestra Camps, al menú dels punts suspensius, seleccioneu Afegeix una targeta personalitzada.

A la subfinestra visualització en arbre, canvieu el nom de la targeta nova de DataCard1 a ReserveCard. A la finestra de la visualització Disseny, torneu a canviar la mida de la targeta per tal que ocupi la part inferior de la pantalla, sota el control Image_DataCard1.

Al menú Insereix, al submenú Entrada, afegiu un control d'entrada de text, un control de botó i un control d'etiqueta al control ReserveCard.
Torneu a canviar la mida i col·locar els controls de manera que quedin de costat, amb el control Botó a la dreta del control Entrada de text, i l'etiqueta a sota del control de botó.
A la subfinestra Propietats del control d'entrada de text, desactiveu la propietat Per defecte.
A la subfinestra Propietats del control Botó, definiu la propietat Text en Per defecte.

Canvieu el nom del control d'entrada de text com a NumberToReserve, canvieu el nom del control del botó com a Reserva i canvieu el nom del control d'etiqueta com a Missatge.
A la subfinestra Propietats del control Missatge, definiu la propietat Text en Peces reservades i definiu la propietat Visible com a MessageIsVisible.
Nota
MessageIsVisible és una variable que inicialitzareu com a fals quan es visualitzi la pantalla, però es canviarà a cert si l'usuari selecciona el botó Reserva.
Definiu la propietat OnSelect del control de botó Reserva en la fórmula següent.
FieldEngineerPartsOrdering.manualinvoke({boilerPartId:ThisItem.id, engineerId:"ab9f4790-05f2-4cc3-9f01-8dfa7d848179", numberToReserve:NumberToReserve.Text}); Set(MessageIsVisible, true);Nota
Aquesta fórmula utilitza un ID d'enginyer amb codi dur per representar el tècnic que executa l'aplicació actualment. El capítol 8 descriu com es recupera l'identificador de l'usuari que ha iniciat la sessió.
A més, l'aplicació no comprova si hi ha cap error. Suposa que la sol·licitud de reserva de peces sempre té èxit. Per obtenir més informació sobre la gestió dels errors, aneu Funció Errors al Power Apps.
Definiu la propietat OnVisible per a la pantalla PartDetails com a Set(MessageIsVisible, false).
Per provar l'aplicació, feu el següent:
A la subfinestra Visualització d'arbre, seleccioneu la pantalla Inici.
Seleccioneu F5 per obtenir una visualització prèvia de l'aplicació.
A la pantalla d'inici, seleccioneu Peces.
A la pantalla de navegació, seleccioneu qualsevol peça.
A la pantalla Detalls de la peça, desplaceu-vos cap avall a la secció de reserves, introduïu un valor enter positiu i, a continuació, seleccioneu Reserva. Verifiqueu que apareix el missatge Peces reservades.

Tanqueu la finestra de visualització prèvia i torneu al Power Apps Studio.
Al portal de l'Azure, aneu a la pàgina de la base de dades SQL inventoryDB.
Seleccioneu Editor de consultes i inicieu sessió com a sqladmin amb la vostra contrasenya.
A la subfinestra Consulta 1, introduïu la consulta següent i seleccioneu Executa. Verifiqueu que apareix la reserva que heu fet a l'aplicació VanArsdel.
SELECT * FROM [dbo].[Reservations]