astuce_dev.html

Martin Toutant, 16/06/2023 17:04

Télécharger (123,724 ko)

 
1
<!DOCTYPE html><html><head>
2
      <title>astuce_dev</title>
3
      <meta charset="utf-8">
4
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
      
6
      <link rel="stylesheet" href="file:///c:\Users\mtoutant\.vscode\extensions\shd101wyy.markdown-preview-enhanced-0.6.8\node_modules\@shd101wyy\mume\dependencies\katex\katex.min.css">
7
      
8
      
9
      
10
      
11
      
12
      
13
      
14
      
15
      
16
      <style>
17
      /**
18
 * prism.js Github theme based on GitHub's theme.
19
 * @author Sam Clarke
20
 */
21
code[class*="language-"],
22
pre[class*="language-"] {
23
  color: #333;
24
  background: none;
25
  font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
26
  text-align: left;
27
  white-space: pre;
28
  word-spacing: normal;
29
  word-break: normal;
30
  word-wrap: normal;
31
  line-height: 1.4;
32

33
  -moz-tab-size: 8;
34
  -o-tab-size: 8;
35
  tab-size: 8;
36

37
  -webkit-hyphens: none;
38
  -moz-hyphens: none;
39
  -ms-hyphens: none;
40
  hyphens: none;
41
}
42

43
/* Code blocks */
44
pre[class*="language-"] {
45
  padding: .8em;
46
  overflow: auto;
47
  /* border: 1px solid #ddd; */
48
  border-radius: 3px;
49
  /* background: #fff; */
50
  background: #f5f5f5;
51
}
52

53
/* Inline code */
54
:not(pre) > code[class*="language-"] {
55
  padding: .1em;
56
  border-radius: .3em;
57
  white-space: normal;
58
  background: #f5f5f5;
59
}
60

61
.token.comment,
62
.token.blockquote {
63
  color: #969896;
64
}
65

66
.token.cdata {
67
  color: #183691;
68
}
69

70
.token.doctype,
71
.token.punctuation,
72
.token.variable,
73
.token.macro.property {
74
  color: #333;
75
}
76

77
.token.operator,
78
.token.important,
79
.token.keyword,
80
.token.rule,
81
.token.builtin {
82
  color: #a71d5d;
83
}
84

85
.token.string,
86
.token.url,
87
.token.regex,
88
.token.attr-value {
89
  color: #183691;
90
}
91

92
.token.property,
93
.token.number,
94
.token.boolean,
95
.token.entity,
96
.token.atrule,
97
.token.constant,
98
.token.symbol,
99
.token.command,
100
.token.code {
101
  color: #0086b3;
102
}
103

104
.token.tag,
105
.token.selector,
106
.token.prolog {
107
  color: #63a35c;
108
}
109

110
.token.function,
111
.token.namespace,
112
.token.pseudo-element,
113
.token.class,
114
.token.class-name,
115
.token.pseudo-class,
116
.token.id,
117
.token.url-reference .token.variable,
118
.token.attr-name {
119
  color: #795da3;
120
}
121

122
.token.entity {
123
  cursor: help;
124
}
125

126
.token.title,
127
.token.title .token.punctuation {
128
  font-weight: bold;
129
  color: #1d3e81;
130
}
131

132
.token.list {
133
  color: #ed6a43;
134
}
135

136
.token.inserted {
137
  background-color: #eaffea;
138
  color: #55a532;
139
}
140

141
.token.deleted {
142
  background-color: #ffecec;
143
  color: #bd2c00;
144
}
145

146
.token.bold {
147
  font-weight: bold;
148
}
149

150
.token.italic {
151
  font-style: italic;
152
}
153

154

155
/* JSON */
156
.language-json .token.property {
157
  color: #183691;
158
}
159

160
.language-markup .token.tag .token.punctuation {
161
  color: #333;
162
}
163

164
/* CSS */
165
code.language-css,
166
.language-css .token.function {
167
  color: #0086b3;
168
}
169

170
/* YAML */
171
.language-yaml .token.atrule {
172
  color: #63a35c;
173
}
174

175
code.language-yaml {
176
  color: #183691;
177
}
178

179
/* Ruby */
180
.language-ruby .token.function {
181
  color: #333;
182
}
183

184
/* Markdown */
185
.language-markdown .token.url {
186
  color: #795da3;
187
}
188

189
/* Makefile */
190
.language-makefile .token.symbol {
191
  color: #795da3;
192
}
193

194
.language-makefile .token.variable {
195
  color: #183691;
196
}
197

198
.language-makefile .token.builtin {
199
  color: #0086b3;
200
}
201

202
/* Bash */
203
.language-bash .token.keyword {
204
  color: #0086b3;
205
}
206

207
/* highlight */
208
pre[data-line] {
209
  position: relative;
210
  padding: 1em 0 1em 3em;
211
}
212
pre[data-line] .line-highlight-wrapper {
213
  position: absolute;
214
  top: 0;
215
  left: 0;
216
  background-color: transparent;
217
  display: block;
218
  width: 100%;
219
}
220

221
pre[data-line] .line-highlight {
222
  position: absolute;
223
  left: 0;
224
  right: 0;
225
  padding: inherit 0;
226
  margin-top: 1em;
227
  background: hsla(24, 20%, 50%,.08);
228
  background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
229
  pointer-events: none;
230
  line-height: inherit;
231
  white-space: pre;
232
}
233

234
pre[data-line] .line-highlight:before, 
235
pre[data-line] .line-highlight[data-end]:after {
236
  content: attr(data-start);
237
  position: absolute;
238
  top: .4em;
239
  left: .6em;
240
  min-width: 1em;
241
  padding: 0 .5em;
242
  background-color: hsla(24, 20%, 50%,.4);
243
  color: hsl(24, 20%, 95%);
244
  font: bold 65%/1.5 sans-serif;
245
  text-align: center;
246
  vertical-align: .3em;
247
  border-radius: 999px;
248
  text-shadow: none;
249
  box-shadow: 0 1px white;
250
}
251

252
pre[data-line] .line-highlight[data-end]:after {
253
  content: attr(data-end);
254
  top: auto;
255
  bottom: .4em;
256
}html body{font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6;color:#333;background-color:#fff;overflow:initial;box-sizing:border-box;word-wrap:break-word}html body>:first-child{margin-top:0}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{line-height:1.2;margin-top:1em;margin-bottom:16px;color:#000}html body h1{font-size:2.25em;font-weight:300;padding-bottom:.3em}html body h2{font-size:1.75em;font-weight:400;padding-bottom:.3em}html body h3{font-size:1.5em;font-weight:500}html body h4{font-size:1.25em;font-weight:600}html body h5{font-size:1.1em;font-weight:600}html body h6{font-size:1em;font-weight:600}html body h1,html body h2,html body h3,html body h4,html body h5{font-weight:600}html body h5{font-size:1em}html body h6{color:#5c5c5c}html body strong{color:#000}html body del{color:#5c5c5c}html body a:not([href]){color:inherit;text-decoration:none}html body a{color:#08c;text-decoration:none}html body a:hover{color:#00a3f5;text-decoration:none}html body img{max-width:100%}html body>p{margin-top:0;margin-bottom:16px;word-wrap:break-word}html body>ul,html body>ol{margin-bottom:16px}html body ul,html body ol{padding-left:2em}html body ul.no-list,html body ol.no-list{padding:0;list-style-type:none}html body ul ul,html body ul ol,html body ol ol,html body ol ul{margin-top:0;margin-bottom:0}html body li{margin-bottom:0}html body li.task-list-item{list-style:none}html body li>p{margin-top:0;margin-bottom:0}html body .task-list-item-checkbox{margin:0 .2em .25em -1.8em;vertical-align:middle}html body .task-list-item-checkbox:hover{cursor:pointer}html body blockquote{margin:16px 0;font-size:inherit;padding:0 15px;color:#5c5c5c;background-color:#f0f0f0;border-left:4px solid #d6d6d6}html body blockquote>:first-child{margin-top:0}html body blockquote>:last-child{margin-bottom:0}html body hr{height:4px;margin:32px 0;background-color:#d6d6d6;border:0 none}html body table{margin:10px 0 15px 0;border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}html body table th{font-weight:bold;color:#000}html body table td,html body table th{border:1px solid #d6d6d6;padding:6px 13px}html body dl{padding:0}html body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:bold}html body dl dd{padding:0 16px;margin-bottom:16px}html body code{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:.85em !important;color:#000;background-color:#f0f0f0;border-radius:3px;padding:.2em 0}html body code::before,html body code::after{letter-spacing:-0.2em;content:"\00a0"}html body pre>code{padding:0;margin:0;font-size:.85em !important;word-break:normal;white-space:pre;background:transparent;border:0}html body .highlight{margin-bottom:16px}html body .highlight pre,html body pre{padding:1em;overflow:auto;font-size:.85em !important;line-height:1.45;border:#d6d6d6;border-radius:3px}html body .highlight pre{margin-bottom:0;word-break:normal}html body pre code,html body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}html body pre code:before,html body pre tt:before,html body pre code:after,html body pre tt:after{content:normal}html body p,html body blockquote,html body ul,html body ol,html body dl,html body pre{margin-top:0;margin-bottom:16px}html body kbd{color:#000;border:1px solid #d6d6d6;border-bottom:2px solid #c7c7c7;padding:2px 4px;background-color:#f0f0f0;border-radius:3px}@media print{html body{background-color:#fff}html body h1,html body h2,html body h3,html body h4,html body h5,html body h6{color:#000;page-break-after:avoid}html body blockquote{color:#5c5c5c}html body pre{page-break-inside:avoid}html body table{display:table}html body img{display:block;max-width:100%;max-height:100%}html body pre,html body code{word-wrap:break-word;white-space:pre}}.markdown-preview{width:100%;height:100%;box-sizing:border-box}.markdown-preview .pagebreak,.markdown-preview .newpage{page-break-before:always}.markdown-preview pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}.markdown-preview pre.line-numbers>code{position:relative}.markdown-preview pre.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:1em;font-size:100%;left:0;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-preview pre.line-numbers .line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.markdown-preview pre.line-numbers .line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.markdown-preview .mathjax-exps .MathJax_Display{text-align:center !important}.markdown-preview:not([for="preview"]) .code-chunk .btn-group{display:none}.markdown-preview:not([for="preview"]) .code-chunk .status{display:none}.markdown-preview:not([for="preview"]) .code-chunk .output-div{margin-bottom:16px}.markdown-preview .md-toc{padding:0}.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link{display:inline;padding:.25rem 0}.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link p,.markdown-preview .md-toc .md-toc-link-wrapper .md-toc-link div{display:inline}.markdown-preview .md-toc .md-toc-link-wrapper.highlighted .md-toc-link{font-weight:800}.scrollbar-style::-webkit-scrollbar{width:8px}.scrollbar-style::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}.scrollbar-style::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode]){position:relative;width:100%;height:100%;top:0;left:0;margin:0;padding:0;overflow:auto}html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{position:relative;top:0}@media screen and (min-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em calc(50% - 457px + 2em)}}@media screen and (max-width:914px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview{font-size:14px !important;padding:1em}}@media print{html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{display:none}}html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn{position:fixed;bottom:8px;left:8px;font-size:28px;cursor:pointer;color:inherit;z-index:99;width:32px;text-align:center;opacity:.4}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn{opacity:1}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc{position:fixed;top:0;left:0;width:300px;height:100%;padding:32px 0 48px 0;font-size:14px;box-shadow:0 0 4px rgba(150,150,150,0.33);box-sizing:border-box;overflow:auto;background-color:inherit}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar{width:8px}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-track{border-radius:10px;background-color:transparent}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc::-webkit-scrollbar-thumb{border-radius:5px;background-color:rgba(150,150,150,0.66);border:4px solid rgba(150,150,150,0.66);background-clip:content-box}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a{text-decoration:none}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc{padding:0 16px}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link{display:inline;padding:.25rem 0}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link p,html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper .md-toc-link div{display:inline}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc .md-toc .md-toc-link-wrapper.highlighted .md-toc-link{font-weight:800}html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{left:300px;width:calc(100% -  300px);padding:2em calc(50% - 457px -  300px/2);margin:0;box-sizing:border-box}@media screen and (max-width:1274px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{padding:2em}}@media screen and (max-width:450px){html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview{width:100%}}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview{left:50%;transform:translateX(-50%)}html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc{display:none}
257
/* Please visit the URL below for more information: */
258
/*   https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */
259

    
260
      </style>
261
    </head>
262
    <body for="html-export">
263
      <div class="mume markdown-preview  ">
264
      <h1 class="mume-header" id="astuces-de-developpement-maui">Astuces de developpement MAUI</h1>
265

    
266
<p>Cette documentation r&#xE9;sume les astuces de d&#xE9;veloppement des applications mobiles MAUI que j&apos;ai apprises lors de mes developpements pour les applications <code>SicpaExpe</code> et <code>SIPMobile</code>. Elle est &#xE0; destination des developpeurs initi&#xE9;s &#xE0; la technologie MAUI, qui cherchent a approfondir leurs connaissances.</p>
267
<p>Si une information est floue, difficile &#xE0; comprendre, ou qu&apos;il manque des d&#xE9;tails, n&apos;h&#xE9;sitez pas &#xE0; m&apos;envoyer un mail &#xE0; <code>martin.toutant1@gmail.com</code> et j&apos;essaierai d&apos;y r&#xE9;pondre le plus rapidement possible.</p>
268
<h2 class="mume-header" id="sommaire">Sommaire</h2>
269

    
270
<ol>
271
<li>Utilisation des services</li>
272
<li>Gestion du mode d&#xE9;connect&#xE9;</li>
273
<li>Appel aux WS REST</li>
274
<li>Permissions sp&#xE9;cifiques fichiers externes Android</li>
275
</ol>
276
<h2 class="mume-header" id="utilisation-des-services">Utilisation des services</h2>
277

    
278
<p>Les services en MAUI sont des classes instanci&#xE9;es une ou plusieurs fois et gard&#xE9;e en m&#xE9;moire, et qui peuvent &#xEA;tre r&#xE9;cup&#xE9;r&#xE9;es et utilis&#xE9;es par les <code>ViewModels</code> par l&apos;injection de d&#xE9;pendances.<br>
279
Plus d&apos;infos sur :</p>
280
<ul>
281
<li><a href="https://learn.microsoft.com/en-us/dotnet/architecture/maui/dependency-injection">https://learn.microsoft.com/en-us/dotnet/architecture/maui/dependency-injection</a> (doc officielle Microsoft, anglais)</li>
282
<li><a href="https://www.e-naxos.com/Blog/post/un-projet-zero-maui-realiste-partie-3-5-modele-services-et-injection-de-dependances.asp">https://www.e-naxos.com/Blog/post/un-projet-zero-maui-realiste-partie-3-5-modele-services-et-injection-de-dependances.asp</a> (DotBlog, fran&#xE7;ais)</li>
283
</ul>
284
<p>Dans les applications <code>SicpaExpe</code> et <code>SIPMobile</code> on retrouve des services communs aux deux applications.</p>
285
<ul>
286
<li>Les services de DAO <code>ServerDAO</code> et <code>LocalDAO</code> qui contiennent les fonctions d&apos;acc&#xE8;s aux donn&#xE9;es sur les diff&#xE9;rentes bases (voir section sur WS REST).</li>
287
<li>Le <code>ConnexionService</code> qui g&#xE8;re l&apos;&#xE9;tat de la connexion.</li>
288
<li>Le <code>LoadingIndicatorService</code> qui permet de g&#xE9;rer l&apos;affichage de l&apos;indicateur de chargement. Permet de n&apos;avoir qu&apos;une seule classe qui g&#xE8;re la propri&#xE9;t&#xE9; <code>IsBusy</code> plutot que de l&apos;avoir dans chaque <code>ViewModel</code>. Permet aussi que des classes hors <code>ViewModels</code> puissent utiliser l&apos;indicateur de chargement.</li>
289
<li>Le <code>SettingsService</code> qui permet de garder quelques variables globales. Par exemple l&apos;unit&#xE9; actuelle dans l&apos;application <code>SIPMobile</code></li>
290
<li>Un service de gestion d&apos;envoi de donn&#xE9;es <code>MouvementService</code> sur <code>SIPMobile</code> et <code>DataSenderService</code> sur <code>SicpaExpe</code>. Cela permet de s&#xE9;parer et de factoriser les fonctions d&apos;envoi des donn&#xE9;es que je laissais auparavant dans les <code>ViewModels</code>.</li>
291
</ul>
292
<p>De plus, MAUI recommande que chaque <code>View</code> et chaque <code>ViewModel</code> soient aussi enregistr&#xE9;s en tant que service. Cela permet de profiter de <strong>l&apos;injection de d&#xE9;pendance</strong> en laissant l&apos;application instancier les classes avec les services dont elles ont besoin.</p>
293
<p>Chaque service doit &#xEA;tre enregistr&#xE9; dans le <code>MauiProgram</code>, point d&apos;entr&#xE9;e du code de l&apos;application. En &#xE9;tant enregistr&#xE9;, il peut ensuite &#xEA;tre inject&#xE9; dans chaque classe qui le demande.</p>
294
<p>Exemple dans l&apos;application <code>SicpaExpe</code>:</p>
295
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-static">static</span> <span class="token return-type class-name">MauiApp</span> <span class="token function">CreateMauiApp</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
296
<span class="token punctuation">{</span>
297
    <span class="token comment">//... </span>
298

    
299
    <span class="token comment">// Enregistrement des services</span>
300
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>LocalDAO<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
301
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ServerDAO<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
302

    
303
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ConnexionService<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
304
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SettingsService<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
305
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>DataSenderService<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
306
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>LoadingIndicatorService<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
307

    
308
    <span class="token comment">// Enregistrement des pages</span>
309
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SelectionExpePage<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
310
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ExpeMainPage<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
311
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddTransient</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SaisieVariablePage<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
312
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SettingsPage<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
313
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddTransient</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>OfflineDataPage<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
314

    
315
    <span class="token comment">// Enregistrement des viewmodels</span>
316
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SelectionExpeViewModel<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
317
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ExpeMainViewModel<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
318
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddTransient</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SaisieVariableViewModel<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
319
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddSingleton</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>SettingsViewModel<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
320
    builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddTransient</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>OfflineDataViewModel<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
321

    
322
    <span class="token comment">// ...</span>
323

    
324
    <span class="token keyword keyword-return">return</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
325
<span class="token punctuation">}</span>
326
</pre><p>Exemple d&apos;un <code>ViewModel</code> demandant six services diff&#xE9;rents :</p>
327
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">ExpeMainViewModel</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ViewModelBase</span><span class="token punctuation">,</span> <span class="token class-name">IRecipient<span class="token punctuation">&lt;</span>ServerResultsLoadedMessage<span class="token punctuation">&gt;</span></span></span>
328
<span class="token punctuation">{</span>
329
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">SettingsService</span> settingsService<span class="token punctuation">;</span>
330
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">LocalDAO</span> localDAO<span class="token punctuation">;</span>
331
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">ServerDAO</span> serverDAO<span class="token punctuation">;</span>
332
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">ConnexionService</span> connService<span class="token punctuation">;</span>
333
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">DataSenderService</span> dataSenderService<span class="token punctuation">;</span>
334
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">LoadingIndicatorService</span> loadingIndicatorService<span class="token punctuation">;</span>
335

    
336
    <span class="token comment">// ...</span>
337

    
338
    <span class="token keyword keyword-public">public</span> <span class="token function">ExpeMainViewModel</span><span class="token punctuation">(</span>
339
        <span class="token class-name">LocalDAO</span> localDAO<span class="token punctuation">,</span> 
340
        <span class="token class-name">ServerDAO</span> serverDAO<span class="token punctuation">,</span> 
341
        <span class="token class-name">SettingsService</span> settingsService<span class="token punctuation">,</span> 
342
        <span class="token class-name">ConnexionService</span> connService<span class="token punctuation">,</span> 
343
        <span class="token class-name">DataSenderService</span> dataSenderService<span class="token punctuation">,</span> 
344
        <span class="token class-name">LoadingIndicatorService</span> loadingIndicatorService<span class="token punctuation">)</span>
345
    <span class="token punctuation">{</span>
346
        <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>localDAO <span class="token operator">=</span> localDAO<span class="token punctuation">;</span>
347
        <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>serverDAO <span class="token operator">=</span> serverDAO<span class="token punctuation">;</span>
348
        <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>settingsService <span class="token operator">=</span> settingsService<span class="token punctuation">;</span>
349
        <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>connService <span class="token operator">=</span> connService<span class="token punctuation">;</span>
350
        <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>dataSenderService <span class="token operator">=</span> dataSenderService<span class="token punctuation">;</span>
351
        <span class="token keyword keyword-this">this</span><span class="token punctuation">.</span>loadingIndicatorService <span class="token operator">=</span> loadingIndicatorService<span class="token punctuation">;</span>
352
        <span class="token comment">// ...</span>
353
    <span class="token punctuation">}</span>
354

    
355
    <span class="token comment">// ...</span>
356

    
357
<span class="token punctuation">}</span>
358
</pre><p>Ce <code>ViewModel</code> est instanci&#xE9; par l&apos;application, et l&apos;application lui <strong>injecte</strong> tous les services donn&#xE9;s en arguments. Le <em>Binding</em> du <code>ViewModel</code> &#xE0; la <code>Page</code> se fait ainsi de la mani&#xE8;re suivante :</p>
359
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token function">ExpeMainPage</span><span class="token punctuation">(</span><span class="token class-name">ExpeMainViewModel</span> vm<span class="token punctuation">)</span>
360
<span class="token punctuation">{</span>
361
    <span class="token function">InitializeComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
362
    BindingContext <span class="token operator">=</span> vm<span class="token punctuation">;</span>
363
    <span class="token comment">// ...</span>
364
<span class="token punctuation">}</span>
365
</pre><p>Comme le <code>ViewModel</code> est enregist&#xE9; en tant que service, il sera aussi inject&#xE9; dans le constructeur de la page, au moment de l&apos;instanciation.</p>
366
<p>NB: Dans le <code>MauiProgram.cs</code> chaque Service peut &#xEA;tre enregistr&#xE9; comme <code>Singleton</code> ou <code>Transient</code>:</p>
367
<ul>
368
<li>En tant que <code>Singleton</code>, il ne sera instanci&#xE9; qu&apos;une seule fois et c&apos;est cette seule et m&#xEA;me instance qui sera utilis&#xE9;e &#xE0; chaque fois quelle sera demand&#xE9;e.</li>
369
<li>En tant que <code>Transient</code>, il sera instanci&#xE9; &#xE0; chaque fois qu&apos;il sera demand&#xE9;.</li>
370
</ul>
371
<p>A garder en t&#xEA;te lorsqu&apos;on d&#xE9;bug ! &#x1F609;</p>
372
<h2 class="mume-header" id="gestion-du-mode-d%C3%A9connect%C3%A9">Gestion du mode d&#xE9;connect&#xE9;</h2>
373

    
374
<p>&#xC0; la suite du hackhaton MAUI qui a eu lieu fin mars, j&apos;ai (re-)r&#xE9;fl&#xE9;chi sur la mise en place du mode d&#xE9;connect&#xE9; dans les applications SicpaExpe puis SIPMobile.</p>
375
<p>Dans cette section, je d&#xE9;cris l&apos;utilisation d&apos;une base de donner locale SQLite en utilisant la librairie <code>sqlite-net-pcl</code>, recommand&#xE9; par la documentation officielle Microsoft. Plus d&apos;informations sur <a href="https://learn.microsoft.com/en-us/dotnet/maui/data-cloud/database-sqlite?view=net-maui-7.0">https://learn.microsoft.com/en-us/dotnet/maui/data-cloud/database-sqlite?view=net-maui-7.0</a></p>
376
<p>Pour des souci de simplicit&#xE9; et pour &#xE9;viter les probl&#xE8;mes de d&#xE9;synchronisation je me suis fix&#xE9; les r&#xE8;gles de d&#xE9;veloppement suivantes :</p>
377
<ul>
378
<li>Toujours aller chercher les donn&#xE9;es dans la base de donn&#xE9;es locale SQLite</li>
379
<li>Minimiser le nombre d&apos;objets stock&#xE9;s comme variable globales</li>
380
<li>Synchroniser avec le serveur seulement lorsque la connexion est &#xE9;tablie</li>
381
</ul>
382
<p>Cela donne le workflow suivant lors de l&apos;enregistrement d&apos;un r&#xE9;sultat sur <code>SicpaExpe</code>, par exemple.</p>
383
<p><img src="data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLSBEbyBub3QgZWRpdCB0aGlzIGZpbGUgd2l0aCBlZGl0b3JzIG90aGVyIHRoYW4gZGlhZ3JhbXMubmV0IC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZlcnNpb249IjEuMSIgd2lkdGg9IjM2MXB4IiBoZWlnaHQ9IjM2MXB4IiB2aWV3Qm94PSItMC41IC0wLjUgMzYxIDM2MSIgY29udGVudD0iJmx0O214ZmlsZSBob3N0PSZxdW90O0VsZWN0cm9uJnF1b3Q7IG1vZGlmaWVkPSZxdW90OzIwMjMtMDYtMTZUMDk6NDM6MDAuMDQ0WiZxdW90OyBhZ2VudD0mcXVvdDs1LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgZHJhdy5pby8xOS4wLjMgQ2hyb21lLzEwMi4wLjUwMDUuNjMgRWxlY3Ryb24vMTkuMC4zIFNhZmFyaS81MzcuMzYmcXVvdDsgZXRhZz0mcXVvdDtmVEljTEpSUEJIM3ZXclRpbEFmbCZxdW90OyB2ZXJzaW9uPSZxdW90OzE5LjAuMyZxdW90OyB0eXBlPSZxdW90O2RldmljZSZxdW90OyZndDsmbHQ7ZGlhZ3JhbSBpZD0mcXVvdDtOTndsV1hEQUVWZkJXOFh1MW9WRSZxdW90OyBuYW1lPSZxdW90O1BhZ2UtMSZxdW90OyZndDs3Vm5iY3Rvd0VQMGFUOXVITUw1akhvRkEybWt5MHhtbVNmb29zTERWeWhZankxenk5VjNaTWtaeFRHaWFRR2JDaXlPdFZxdkwyYlBhRFlZelROWlhIQzNpR3haaWF0aG11RGFjUzhPMkxkTUo0SStVYkVxSjcvVktRY1JKcUpScXdZUTg0R3Fta3VZa3hKbW1LQmlqZ2l4MDRZeWxLWjRKVFlZNFp5dGRiYzZvdnVvQ1JiZ2htTXdRYlVydlNDamlVdG96elZyK0ZaTW9ybGIycTVFRVZjcEtrTVVvWktzZGtUTXluQ0ZuVEpTdFpEM0VWRjVlZFMvbHZISEw2SFpqSEtmaWtBbmpoSXZSWGZmMmUvOE85L2lmcTBuQzdpOTh0VGV4cVE2TVF6aS82akl1WWhheEZORlJMUjF3bHFjaGxsWk42TlU2MTR3dFFHaUI4RGNXWXFQQVJMbGdJSXBGUXRVb2JKaHY3dVg4amxkMWZ5bHpSZWR5cmZVMnFqZG5xUmlqaEZBcCtEbk5VNUhEM205WXl0VGdoT1Y4SnRlTWhRRC9zRDJuRHgrNEVmbVJDbGtuWWl5aUdDMUkxcG14cEJpWVpZWHFlRjZhaHViV3VHY1BkczJYQjdJQXVrRjViL0t5V3VGUW9xemFWQnNHbFZzakhtR3hSOC9aT2cyd0RiTUV3OTNBUEk0cEVtU3A3d01wdDQrMmVyVm5RRU01eHo4NGlySzdSRFJYSzQxU2ppT1NDWTRUZVdTZytLYzhsZnN4aG83UjcyVTVGVWcwM0V0M25sVk1CSjRzVUhFL0s0Z2d1cU84UDhDWG1BdTgzZzk1RTZKcWdxOUN3ZVpSZjFWSEZxc0tGL0ZPVkhITk4wTFZPd1g5M3grcXIwSmo1MEFhdXllbHNkM2c4UmpsNnlmZDRCcE40VEhYb0VPVVJDbTBaM0E3bUlOQThvSEFhOWxYQXdrSnc5SkxjRVllMExTd0ovMWt3UWpnSm8xN0E4TzdmQUtLdlc3UnlqNzE3cXVWNnRkMkY4RjIxMitsNm9YWk1idVdxOUZWWGQzQlFDbmpQK1RKYTh1MnB4bTlzSFVEYkQ3UHNHamd2TjNoeTZIdm5ibCtkSzRISitXNjArRDZMVWZrQTNLOTl4elhmYTlydlFxN0xmOVlkRzZDTzFRbFVKRitHYzY0bVh2RkxKbm0yY2ZMdXdJOTc5cm1VenQ1VjNETXRLc3FiczlsMXdsanVIdGdETytlTW9hN0RaWi9TME1Jd2dMblhKWmNXSDZBOXlYcFpRL0xHZ3dKSWFPMllmc1VqamFZZ3E0ZnlkYm5DUlJsRUFJZ2RFcHJwdldsR1NVK2NJWG02b0hDc1E4czBJSzNpaFRkQnY2TnNyc0FuREo0bU05UTdpbTIzZURVeGJabE5RQTZaK0F2amQ3L20xbTNGR2QyaTlOVUpzclhRczJxL2FIUE9kcnNxS2tNdUhVZDUxR2djZDFILzd0OWJsKzZQalRLSGJ4cWhoazhFWHVXak1oalNoZktNRjhXcjlCemI0eDVmbU4yQTVNZEhPK1JnVzc5QTBQcEYvWFBOTTdvTHc9PSZsdDsvZGlhZ3JhbSZndDsmbHQ7L214ZmlsZSZndDsiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7Ij48ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPkBpbXBvcnQgdXJsKGh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzP2ZhbWlseT1SZWQrSGF0K01vbm8pOyYjeGE7QGltcG9ydCB1cmwoaHR0cHM6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3M/ZmFtaWx5PVVidW50dStNb25vKTsmI3hhOzwvc3R5bGU+PC9kZWZzPjxnPjxwYXRoIGQ9Ik0gMTgwIDQwIEwgMTgwIDczLjYzIiBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0ic3Ryb2tlIi8+PHBhdGggZD0iTSAxODAgNzguODggTCAxNzYuNSA3MS44OCBMIDE4MCA3My42MyBMIDE4My41IDcxLjg4IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxyZWN0IHg9IjEyMCIgeT0iMCIgd2lkdGg9IjEyMCIgaGVpZ2h0PSI0MCIgZmlsbD0icmdiKDI1NSwgMjU1LCAyNTUpIiBzdHJva2U9InJnYigwLCAwLCAwKSIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAxMThweDsgaGVpZ2h0OiAxcHg7IHBhZGRpbmctdG9wOiAyMHB4OyBtYXJnaW4tbGVmdDogMTIxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPkVucmVnaXN0cmVtZW50IGQndW4gcsOpc3VsdGF0PC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjE4MCIgeT0iMjQiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IlVidW50dSBNb25vIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkVucmVnaXN0cmVtZW50IGQndW4uLi48L3RleHQ+PC9zd2l0Y2g+PC9nPjxwYXRoIGQ9Ik0gMTQwIDEwMCBMIDYwIDEwMCBMIDYwIDE1My42MyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9InN0cm9rZSIvPjxwYXRoIGQ9Ik0gNjAgMTU4Ljg4IEwgNTYuNSAxNTEuODggTCA2MCAxNTMuNjMgTCA2My41IDE1MS44OCBaIiBmaWxsPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC41IC0wLjUpIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHBvaW50ZXItZXZlbnRzPSJub25lIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiByZXF1aXJlZEZlYXR1cmVzPSJodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0V4dGVuc2liaWxpdHkiIHN0eWxlPSJvdmVyZmxvdzogdmlzaWJsZTsgdGV4dC1hbGlnbjogbGVmdDsiPjxkaXYgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogdW5zYWZlIGNlbnRlcjsganVzdGlmeS1jb250ZW50OiB1bnNhZmUgY2VudGVyOyB3aWR0aDogMXB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDEwMXB4OyBtYXJnaW4tbGVmdDogMTAxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgYmFja2dyb3VuZC1jb2xvcjogcmdiKDI1NSwgMjU1LCAyNTUpOyAiIHN0eWxlPSJib3gtc2l6aW5nOiBib3JkZXItYm94OyBmb250LXNpemU6IDBweDsgdGV4dC1hbGlnbjogY2VudGVyOyI+PGRpdiBzdHlsZT0iZGlzcGxheTogaW5saW5lLWJsb2NrOyBmb250LXNpemU6IDEycHg7IGZvbnQtZmFtaWx5OiAmcXVvdDtVYnVudHUgTW9ubyZxdW90OzsgY29sb3I6IHJnYigwLCAwLCAwKTsgbGluZS1oZWlnaHQ6IDEuMjsgcG9pbnRlci1ldmVudHM6IGFsbDsgYmFja2dyb3VuZC1jb2xvcjogcmdiKDI1NSwgMjU1LCAyNTUpOyB3aGl0ZS1zcGFjZTogbm93cmFwOyI+RmF1eDwvZGl2PjwvZGl2PjwvZGl2PjwvZm9yZWlnbk9iamVjdD48dGV4dCB4PSIxMDEiIHk9IjEwNCIgZmlsbD0icmdiKDAsIDAsIDApIiBmb250LWZhbWlseT0iVWJ1bnR1IE1vbm8iIGZvbnQtc2l6ZT0iMTJweCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+RmF1eDwvdGV4dD48L3N3aXRjaD48L2c+PHBhdGggZD0iTSAyMjAgMTAwIEwgMzAwIDEwMCBMIDMwMCAxNTMuNjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDMwMCAxNTguODggTCAyOTYuNSAxNTEuODggTCAzMDAgMTUzLjYzIEwgMzAzLjUgMTUxLjg4IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAxcHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogMTAxcHg7IG1hcmdpbi1sZWZ0OiAyNjFweDsiPjxkaXYgZGF0YS1kcmF3aW8tY29sb3JzPSJjb2xvcjogcmdiKDAsIDAsIDApOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7ICIgc3R5bGU9ImJveC1zaXppbmc6IGJvcmRlci1ib3g7IGZvbnQtc2l6ZTogMHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij48ZGl2IHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGZvbnQtc2l6ZTogMTJweDsgZm9udC1mYW1pbHk6ICZxdW90O1VidW50dSBNb25vJnF1b3Q7OyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7IHdoaXRlLXNwYWNlOiBub3dyYXA7Ij5WcmFpPC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjI2MSIgeT0iMTA0IiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJVYnVudHUgTW9ubyIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5WcmFpPC90ZXh0Pjwvc3dpdGNoPjwvZz48cGF0aCBkPSJNIDE4MCA4MCBMIDIyMCAxMDAgTCAxODAgMTIwIEwgMTQwIDEwMCBaIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC41IC0wLjUpIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHBvaW50ZXItZXZlbnRzPSJub25lIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiByZXF1aXJlZEZlYXR1cmVzPSJodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0V4dGVuc2liaWxpdHkiIHN0eWxlPSJvdmVyZmxvdzogdmlzaWJsZTsgdGV4dC1hbGlnbjogbGVmdDsiPjxkaXYgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogdW5zYWZlIGNlbnRlcjsganVzdGlmeS1jb250ZW50OiB1bnNhZmUgY2VudGVyOyB3aWR0aDogNzhweDsgaGVpZ2h0OiAxcHg7IHBhZGRpbmctdG9wOiAxMDBweDsgbWFyZ2luLWxlZnQ6IDE0MXB4OyI+PGRpdiBkYXRhLWRyYXdpby1jb2xvcnM9ImNvbG9yOiByZ2IoMCwgMCwgMCk7ICIgc3R5bGU9ImJveC1zaXppbmc6IGJvcmRlci1ib3g7IGZvbnQtc2l6ZTogMHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij48ZGl2IHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGZvbnQtc2l6ZTogMTJweDsgZm9udC1mYW1pbHk6ICZxdW90O1VidW50dSBNb25vJnF1b3Q7OyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyB3aGl0ZS1zcGFjZTogbm9ybWFsOyBvdmVyZmxvdy13cmFwOiBub3JtYWw7Ij5Db25uZWN0w6k/PC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjE4MCIgeT0iMTA0IiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJVYnVudHUgTW9ubyIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Db25uZWN0w6k/PC90ZXh0Pjwvc3dpdGNoPjwvZz48cGF0aCBkPSJNIDYwIDI0MCBMIDYwIDI4MCBMIDE4MCAyODAgTCAxODAgMzEzLjYzIiBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0ic3Ryb2tlIi8+PHBhdGggZD0iTSAxODAgMzE4Ljg4IEwgMTc2LjUgMzExLjg4IEwgMTgwIDMxMy42MyBMIDE4My41IDMxMS44OCBaIiBmaWxsPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48cmVjdCB4PSIwIiB5PSIxNjAiIHdpZHRoPSIxMjAiIGhlaWdodD0iODAiIGZpbGw9InJnYigyNTUsIDI1NSwgMjU1KSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC41IC0wLjUpIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHBvaW50ZXItZXZlbnRzPSJub25lIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiByZXF1aXJlZEZlYXR1cmVzPSJodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0V4dGVuc2liaWxpdHkiIHN0eWxlPSJvdmVyZmxvdzogdmlzaWJsZTsgdGV4dC1hbGlnbjogbGVmdDsiPjxkaXYgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogdW5zYWZlIGNlbnRlcjsganVzdGlmeS1jb250ZW50OiB1bnNhZmUgY2VudGVyOyB3aWR0aDogMTE4cHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogMjAwcHg7IG1hcmdpbi1sZWZ0OiAxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPkluZGljYXRldXIgZGUgZG9ubsOpZSBlbiBhdHRlbnRlPGJyIC8+KFN0YXR1cyA9IDEpPC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjYwIiB5PSIyMDQiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IlVidW50dSBNb25vIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkluZGljYXRldXIgZGUgZG9ubsOpZS4uLjwvdGV4dD48L3N3aXRjaD48L2c+PHJlY3QgeD0iMTIwIiB5PSIzMjAiIHdpZHRoPSIxMjAiIGhlaWdodD0iNDAiIGZpbGw9InJnYigyNTUsIDI1NSwgMjU1KSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC41IC0wLjUpIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHBvaW50ZXItZXZlbnRzPSJub25lIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiByZXF1aXJlZEZlYXR1cmVzPSJodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0V4dGVuc2liaWxpdHkiIHN0eWxlPSJvdmVyZmxvdzogdmlzaWJsZTsgdGV4dC1hbGlnbjogbGVmdDsiPjxkaXYgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogdW5zYWZlIGNlbnRlcjsganVzdGlmeS1jb250ZW50OiB1bnNhZmUgY2VudGVyOyB3aWR0aDogMTE4cHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogMzQwcHg7IG1hcmdpbi1sZWZ0OiAxMjFweDsiPjxkaXYgZGF0YS1kcmF3aW8tY29sb3JzPSJjb2xvcjogcmdiKDAsIDAsIDApOyAiIHN0eWxlPSJib3gtc2l6aW5nOiBib3JkZXItYm94OyBmb250LXNpemU6IDBweDsgdGV4dC1hbGlnbjogY2VudGVyOyI+PGRpdiBzdHlsZT0iZGlzcGxheTogaW5saW5lLWJsb2NrOyBmb250LXNpemU6IDEycHg7IGZvbnQtZmFtaWx5OiAmcXVvdDtVYnVudHUgTW9ubyZxdW90OzsgY29sb3I6IHJnYigwLCAwLCAwKTsgbGluZS1oZWlnaHQ6IDEuMjsgcG9pbnRlci1ldmVudHM6IGFsbDsgd2hpdGUtc3BhY2U6IG5vcm1hbDsgb3ZlcmZsb3ctd3JhcDogbm9ybWFsOyI+RW5yZWdpc3RyZW1lbnQgZW4gbG9jYWw8L2Rpdj48L2Rpdj48L2Rpdj48L2ZvcmVpZ25PYmplY3Q+PHRleHQgeD0iMTgwIiB5PSIzNDQiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IlVidW50dSBNb25vIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkVucmVnaXN0cmVtZW50IGVuIGxvLi4uPC90ZXh0Pjwvc3dpdGNoPjwvZz48cGF0aCBkPSJNIDMwMCAyNDAgTCAzMDAgMjgwIEwgMTgwIDI4MCBMIDE4MCAzMTMuNjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDE4MCAzMTguODggTCAxNzYuNSAzMTEuODggTCAxODAgMzEzLjYzIEwgMTgzLjUgMzExLjg4IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxyZWN0IHg9IjI0MCIgeT0iMTYwIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjgwIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDExOHB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDIwMHB4OyBtYXJnaW4tbGVmdDogMjQxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPkVudm9pIGF1IHNlcnZldXI8YnIgLz4oU3RhdHVzID0gMCk8L2Rpdj48L2Rpdj48L2Rpdj48L2ZvcmVpZ25PYmplY3Q+PHRleHQgeD0iMzAwIiB5PSIyMDQiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IlVidW50dSBNb25vIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPkVudm9pIGF1IHNlcnZldXIuLi48L3RleHQ+PC9zd2l0Y2g+PC9nPjwvZz48c3dpdGNoPjxnIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIvPjxhIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTUpIiB4bGluazpocmVmPSJodHRwczovL3d3dy5kaWFncmFtcy5uZXQvZG9jL2ZhcS9zdmctZXhwb3J0LXRleHQtcHJvYmxlbXMiIHRhcmdldD0iX2JsYW5rIj48dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LXNpemU9IjEwcHgiIHg9IjUwJSIgeT0iMTAwJSI+VGV4dCBpcyBub3QgU1ZHIC0gY2Fubm90IGRpc3BsYXk8L3RleHQ+PC9hPjwvc3dpdGNoPjwvc3ZnPg==" alt="graph mode deco"></p>
384
<p>Pour synchroniser les donn&#xE9;es, au lancement de l&apos;application et lors du r&#xE9;tablissement de la connexion, l&apos;application v&#xE9;rifie s&apos;il existe des donn&#xE9;es en attente d&apos;envoi (i.e. <code>Status == 1</code>) et les envoie. Puis toutes les donn&#xE9;es locales sont supprim&#xE9;es (fonction <code>ClearDataFromTable&lt;T&gt;</code>) et ensuite re-t&#xE9;l&#xE9;charg&#xE9;es depuis le serveur.</p>
385
<p><img src="data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLSBEbyBub3QgZWRpdCB0aGlzIGZpbGUgd2l0aCBlZGl0b3JzIG90aGVyIHRoYW4gZGlhZ3JhbXMubmV0IC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZlcnNpb249IjEuMSIgd2lkdGg9IjI2MnB4IiBoZWlnaHQ9IjM4MnB4IiB2aWV3Qm94PSItMC41IC0wLjUgMjYyIDM4MiIgY29udGVudD0iJmx0O214ZmlsZSBob3N0PSZxdW90O0VsZWN0cm9uJnF1b3Q7IG1vZGlmaWVkPSZxdW90OzIwMjMtMDYtMTZUMDk6NTY6MTkuMTY5WiZxdW90OyBhZ2VudD0mcXVvdDs1LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgZHJhdy5pby8xOS4wLjMgQ2hyb21lLzEwMi4wLjUwMDUuNjMgRWxlY3Ryb24vMTkuMC4zIFNhZmFyaS81MzcuMzYmcXVvdDsgZXRhZz0mcXVvdDs0SEFpWFZXdC14NFo0REE2dF9HMSZxdW90OyB2ZXJzaW9uPSZxdW90OzE5LjAuMyZxdW90OyB0eXBlPSZxdW90O2RldmljZSZxdW90OyZndDsmbHQ7ZGlhZ3JhbSBpZD0mcXVvdDtQaHdFbG5qOFVYczE1czZ4bkljbSZxdW90OyBuYW1lPSZxdW90O1BhZ2UtMSZxdW90OyZndDs3VmxkazlvMkZQMDFucllQeS9nRGI5YVBDeXpkZG5ZN21hRnAya2RoQzFzWjI5ZVJaY0Q1OWIyeVpCdWp3Skx1RWpvVFhrQTZrcTZrZSs2NWtzRHlwdG4yVjA2SzVCa2ltbHF1SFcwdGIyYTVidURjNGFjRWFnWDQ0MEFCTVdlUmdwd2VXTEF2VklPMlJpc1cwWExRVVFDa2doVkRNSVE4cDZFWVlJUnoyQXk3clNBZHpscVFtQnJBSWlTcGlYNWtrVWowdG15N3h4OHBpNU4yNXR1MkpTTnRadzJVQ1lsZ3N3TjVENVkzNVFCQ2xiTHRsS2JTZDYxZjFMajVnZFp1WVp6bTRwUUJqK0Z6L2ZseCt1SDNQejU5Zkh4YS96WmZCUG5OTzcwMlViY2JwaEh1WDFlQml3Uml5RW42MEtNVERsVWVVV25WeGxyZjV3bWdRTkJCOEJNVm90Wmtra29BUW9uSVV0MjZnbHpNU2NaU0dSTWZsbFV1S2x6RE0rU2dHeGRROFZDT1RZUkFubDNmdThjUDNKbjhrQjNLVVF3UXA1UVVyQnlGa0RVTllkbDBuYStVYVN4MnhuMTNvczJyL2NwTkhuU2poc3AyRVlkODE0WWo0VEVWUi9xNUhka29FZ29aRlJ4WFozT2FFc0hXdzNVUUhhNXgxNjluRkF1YTFHOGdXTnRkazdUU015M3FQRXc0NUt6RTZTRTNBbUJJN3laaGdpNEswbmhpZ3hMLy8xRFptRmN4NXJnZHRXdktCZDBlSjlja1k5dkpWdzJwOStxYlh2dE9LK2hrUi9kaiswejgzUm44WFJYN254WHJucWhZNzVXS2JZYmVjMDdxblE0Rk1IVERqdVgzRXVoano5dUxQVGZ3OTZKSFdleGpxVnZhSzlLRFo4VFhYNXl3cjhiWUUxbmkyVDZJQzVLeU9NZHlpRlJRam9CVUg4UFQ4MTQzWkN5S1ZBalNrbjBoeThhZURFTHREVFR1VHl4LzlsS01IZFMyUHZlMTVmNjAzUTJQdzhJNm1BanMwVHZIY1laOHFOcTNCWUhCOG8zdkRxemVPSHVaQTFhckVvTnpQMis4QWRmQkpUSUhrc0Rydi9YNHB2S1BySXo4dGpyYjdqYk9hbDI3Wk1acFZ2S2Vjb1llbDFIZExPZ0NhV2g4aVRUVUtVZ0g2Tmo5SG1uSU5kTFFuRlRiSHlBTkJVZlQwSTA5R3R0M2I1bUd6cDltVENvdDl6WVYyclh5RFVhME9tNC9WL0x4TXhsNnVZT3hGTXZ2R2ZyV21ucldmWUFQUVpSZ0xyY2hoT1JhUGl4L292a2E4TVJDT3VmdFRFdmVEdjU1SVlpb3lxWjUxc3hxTzcrWTNWckVVcm1qaC9jdnh3bGtTelQzNHNYNERKZlI3cEw1MG1YVTJUOVQzdTQxWVJzZXVkNCtUMDM3M25kSys2OWkyTHdQUG1oNVJZMzZvcUVZVTVBL2xjZ1NTSFFTbU5MNmlnQk5XZjNBYjA3UEhzcmNjMCtVdVg4Mmxac0VYVlYrcXNySEo2cmN2NlRLeDRiS0YxVlI0T1dvYkg0UlFxM0xMVUFsbE1pUEt2OHE1WU5TSHR1WGxySnZFUDJuNGpCVlgyRWk0elNqemNYc0JOWkx5dGUwNGxmV2o3RWVuSTkxclBiL0dLZ2JlLyszaS9md0x3PT0mbHQ7L2RpYWdyYW0mZ3Q7Jmx0Oy9teGZpbGUmZ3Q7IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogcmdiKDI1NSwgMjU1LCAyNTUpOyI+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj5AaW1wb3J0IHVybChodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tL2Nzcz9mYW1pbHk9VWJ1bnR1K01vbm8pOyYjeGE7QGltcG9ydCB1cmwoaHR0cHM6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3M/ZmFtaWx5PVJlZCtIYXQrTW9ubyk7JiN4YTs8L3N0eWxlPjwvZGVmcz48Zz48cGF0aCBkPSJNIDYwIDQwIEwgNjAgNzMuNjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDYwIDc4Ljg4IEwgNTYuNSA3MS44OCBMIDYwIDczLjYzIEwgNjMuNSA3MS44OCBaIiBmaWxsPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjQwIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDExOHB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDIwcHg7IG1hcmdpbi1sZWZ0OiAxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPlN5bmNocm9uaXNhdGlvbjwvZGl2PjwvZGl2PjwvZGl2PjwvZm9yZWlnbk9iamVjdD48dGV4dCB4PSI2MCIgeT0iMjQiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IlVidW50dSBNb25vIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlN5bmNocm9uaXNhdGlvbjwvdGV4dD48L3N3aXRjaD48L2c+PHBhdGggZD0iTSAxMjAgMTM1IEwgMjAwIDEzNSBMIDIwMCAxNTMuNjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDIwMCAxNTguODggTCAxOTYuNSAxNTEuODggTCAyMDAgMTUzLjYzIEwgMjAzLjUgMTUxLjg4IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAxcHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogMTM1cHg7IG1hcmdpbi1sZWZ0OiAxNTBweDsiPjxkaXYgZGF0YS1kcmF3aW8tY29sb3JzPSJjb2xvcjogcmdiKDAsIDAsIDApOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7ICIgc3R5bGU9ImJveC1zaXppbmc6IGJvcmRlci1ib3g7IGZvbnQtc2l6ZTogMHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij48ZGl2IHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGZvbnQtc2l6ZTogMTFweDsgZm9udC1mYW1pbHk6ICZxdW90O1VidW50dSBNb25vJnF1b3Q7OyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7IHdoaXRlLXNwYWNlOiBub3dyYXA7Ij5WcmFpPC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjE1MCIgeT0iMTM5IiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJVYnVudHUgTW9ubyIgZm9udC1zaXplPSIxMXB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5WcmFpPC90ZXh0Pjwvc3dpdGNoPjwvZz48cGF0aCBkPSJNIDYwIDE5MCBMIDYwIDI2NSBMIDEzMy42MyAyNjUiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDEzOC44OCAyNjUgTCAxMzEuODggMjY4LjUgTCAxMzMuNjMgMjY1IEwgMTMxLjg4IDI2MS41IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAxcHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogMjM2cHg7IG1hcmdpbi1sZWZ0OiA2MnB4OyI+PGRpdiBkYXRhLWRyYXdpby1jb2xvcnM9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGJhY2tncm91bmQtY29sb3I6IHJnYigyNTUsIDI1NSwgMjU1KTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMXB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IGJhY2tncm91bmQtY29sb3I6IHJnYigyNTUsIDI1NSwgMjU1KTsgd2hpdGUtc3BhY2U6IG5vd3JhcDsiPkZhdXg8L2Rpdj48L2Rpdj48L2Rpdj48L2ZvcmVpZ25PYmplY3Q+PHRleHQgeD0iNjIiIHk9IjI0MCIgZmlsbD0icmdiKDAsIDAsIDApIiBmb250LWZhbWlseT0iVWJ1bnR1IE1vbm8iIGZvbnQtc2l6ZT0iMTFweCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+RmF1eDwvdGV4dD48L3N3aXRjaD48L2c+PHBhdGggZD0iTSA2MCA4MCBMIDEyMCAxMzUgTCA2MCAxOTAgTCAwIDEzNSBaIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC41IC0wLjUpIj48c3dpdGNoPjxmb3JlaWduT2JqZWN0IHBvaW50ZXItZXZlbnRzPSJub25lIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiByZXF1aXJlZEZlYXR1cmVzPSJodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0V4dGVuc2liaWxpdHkiIHN0eWxlPSJvdmVyZmxvdzogdmlzaWJsZTsgdGV4dC1hbGlnbjogbGVmdDsiPjxkaXYgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHN0eWxlPSJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogdW5zYWZlIGNlbnRlcjsganVzdGlmeS1jb250ZW50OiB1bnNhZmUgY2VudGVyOyB3aWR0aDogMTE4cHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogMTM1cHg7IG1hcmdpbi1sZWZ0OiAxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogSGVsdmV0aWNhOyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyB3aGl0ZS1zcGFjZTogbm9ybWFsOyBvdmVyZmxvdy13cmFwOiBub3JtYWw7Ij48Zm9udCBmYWNlPSJVYnVudHUgTW9ubyI+RG9ubsOpZXMgZW4gYXR0ZW50ZSBkJ2Vudm9pID88YnIgLz4oU3RhdHVzID09IDEpPGJyIC8+PC9mb250PjwvZGl2PjwvZGl2PjwvZGl2PjwvZm9yZWlnbk9iamVjdD48dGV4dCB4PSI2MCIgeT0iMTM5IiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJIZWx2ZXRpY2EiIGZvbnQtc2l6ZT0iMTJweCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+RG9ubsOpZXMgZW4gYXR0ZW50ZSBkLi4uPC90ZXh0Pjwvc3dpdGNoPjwvZz48cGF0aCBkPSJNIDIwMCAyMTAgTCAyMDAgMjMwIEwgMjAwIDIyMCBMIDIwMCAyMzMuNjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDIwMCAyMzguODggTCAxOTYuNSAyMzEuODggTCAyMDAgMjMzLjYzIEwgMjAzLjUgMjMxLjg4IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxyZWN0IHg9IjE0MCIgeT0iMTYwIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjUwIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDExOHB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDE4NXB4OyBtYXJnaW4tbGVmdDogMTQxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPkVudm9pIGRlcyBkb25uw6llcyBsb2NhbGVzIG/DuTxiciAvPlN0YXR1cyA9PSAxPC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjIwMCIgeT0iMTg5IiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJVYnVudHUgTW9ubyIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5FbnZvaSBkZXMgZG9ubsOpZXMgbG8uLi48L3RleHQ+PC9zd2l0Y2g+PC9nPjxwYXRoIGQ9Ik0gMjAwIDI5MCBMIDIwMCAzMjMuNjMiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDIwMCAzMjguODggTCAxOTYuNSAzMjEuODggTCAyMDAgMzIzLjYzIEwgMjAzLjUgMzIxLjg4IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxyZWN0IHg9IjE0MCIgeT0iMjQwIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjUwIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDExOHB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDI2NXB4OyBtYXJnaW4tbGVmdDogMTQxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPlN1cHByZXNzaW9uIGRlIHRvdXRlcyBsZXMgZG9ubsOpZXMgbG9jYWxlczwvZGl2PjwvZGl2PjwvZGl2PjwvZm9yZWlnbk9iamVjdD48dGV4dCB4PSIyMDAiIHk9IjI2OSIgZmlsbD0icmdiKDAsIDAsIDApIiBmb250LWZhbWlseT0iVWJ1bnR1IE1vbm8iIGZvbnQtc2l6ZT0iMTJweCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+U3VwcHJlc3Npb24gZGUgdG91dGUuLi48L3RleHQ+PC9zd2l0Y2g+PC9nPjxyZWN0IHg9IjE0MCIgeT0iMzMwIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjUwIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDExOHB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDM1NXB4OyBtYXJnaW4tbGVmdDogMTQxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogJnF1b3Q7VWJ1bnR1IE1vbm8mcXVvdDs7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPlTDqWzDqWNoYXJnZW1lbnQgZGUgdG91dGVzIGxlcyBkb25uw6llcyBzZXJ2ZXVyPC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjIwMCIgeT0iMzU5IiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJVYnVudHUgTW9ubyIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5Uw6lsw6ljaGFyZ2VtZW50IGRlIHRvLi4uPC90ZXh0Pjwvc3dpdGNoPjwvZz48L2c+PHN3aXRjaD48ZyByZXF1aXJlZEZlYXR1cmVzPSJodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0V4dGVuc2liaWxpdHkiLz48YSB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLC01KSIgeGxpbms6aHJlZj0iaHR0cHM6Ly93d3cuZGlhZ3JhbXMubmV0L2RvYy9mYXEvc3ZnLWV4cG9ydC10ZXh0LXByb2JsZW1zIiB0YXJnZXQ9Il9ibGFuayI+PHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1zaXplPSIxMHB4IiB4PSI1MCUiIHk9IjEwMCUiPlRleHQgaXMgbm90IFNWRyAtIGNhbm5vdCBkaXNwbGF5PC90ZXh0PjwvYT48L3N3aXRjaD48L3N2Zz4=" alt="graph synchro"></p>
386
<p>Exemple de fonction de r&#xE9;cup&#xE9;ration des r&#xE9;sultats en attente d&apos;envoi dans la base SQLite de l&apos;application <code>SicpaExpe</code> :</p>
387
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>List<span class="token punctuation">&lt;</span>Resultat<span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">GetToSendResultats</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
388
<span class="token punctuation">{</span>
389
    <span class="token keyword keyword-await">await</span> <span class="token function">Init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
390
    <span class="token keyword keyword-return">return</span> 
391
        <span class="token keyword keyword-await">await</span> conn<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Table</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Resultat<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
392
            <span class="token punctuation">.</span><span class="token function">Where</span><span class="token punctuation">(</span>r <span class="token operator">=&gt;</span> r<span class="token punctuation">.</span>Status <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span>
393
            <span class="token punctuation">.</span><span class="token function">ToListAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
394
<span class="token punctuation">}</span>
395
</pre><p>Exemple de resynchronisation des donn&#xE9;es dans <code>SicpaExpe</code> (et de l&apos;utilisation du <code>LoadingIndicatorService</code>):</p>
396
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token comment">// R&#xE9;cup&#xE9;ration des r&#xE9;sultats locaux</span>
397
<span class="token class-name">List<span class="token punctuation">&lt;</span>Resultat<span class="token punctuation">&gt;</span></span> toSendResults <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> localDAO<span class="token punctuation">.</span><span class="token function">GetToSendResultats</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
398
<span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>toSendResults<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
399
<span class="token punctuation">{</span>
400
    loadingIndicatorService<span class="token punctuation">.</span>LoadingMessage <span class="token operator">=</span> <span class="token string">&quot;Envoi des r&#xE9;sultats locaux...&quot;</span><span class="token punctuation">;</span>
401
    <span class="token keyword keyword-await">await</span> <span class="token function">SendResultatsToServerAsync</span><span class="token punctuation">(</span>toSendResults<span class="token punctuation">)</span><span class="token punctuation">;</span>
402
<span class="token punctuation">}</span>
403

    
404
loadingIndicatorService<span class="token punctuation">.</span>LoadingMessage <span class="token operator">=</span> <span class="token string">&quot;Sauvegarde des r&#xE9;sultats de la base...&quot;</span><span class="token punctuation">;</span>
405
<span class="token class-name">List<span class="token punctuation">&lt;</span>Resultat<span class="token punctuation">&gt;</span></span> allResults <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> serverDAO<span class="token punctuation">.</span><span class="token function">GetAllResultats</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
406
<span class="token keyword keyword-await">await</span> localDAO<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ClearDataFromTableAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Resultat<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
407
<span class="token keyword keyword-await">await</span> localDAO<span class="token punctuation">.</span><span class="token function">SaveItems</span><span class="token punctuation">(</span>allResults<span class="token punctuation">)</span><span class="token punctuation">;</span>
408

    
409
<span class="token class-name">List<span class="token punctuation">&lt;</span><span class="token keyword keyword-int">int</span><span class="token punctuation">&gt;</span></span> concernedAnimals <span class="token operator">=</span> allResults<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>r <span class="token operator">=&gt;</span> r<span class="token punctuation">.</span>AnimalID<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
410
WeakReferenceMessenger<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">Send</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ServerResultsLoadedMessage</span><span class="token punctuation">(</span>concernedAnimals<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
411
Toast<span class="token punctuation">.</span><span class="token function">Make</span><span class="token punctuation">(</span><span class="token string">&quot;Synchronisation des r&#xE9;sultats avec le serveur effectu&#xE9;e.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
412
loadingIndicatorService<span class="token punctuation">.</span>IsBusy <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
413
</pre><p>Dans l&apos;application <code>SicpaExpe</code>, les donn&#xE9;es sont synchronis&#xE9;es syst&#xE9;matiquement &#xE0; chaque reconnexion, en utilisant l&apos;&#xE9;v&#xE8;nement <code>Connectivity.ConnectivityChanged</code> et l&apos;outil Messagerie de la librairie <code>MVVM Toolkit</code> de microsoft.<br>
414
Plus d&apos;infos sur :</p>
415
<ul>
416
<li><a href="https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/messenger">https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/messenger</a> (doc officielle Microsoft, anglais)</li>
417
<li><a href="https://www.e-naxos.com/Blog/post/Microsoft-MVVM-Toolkit-Partie-5.aspx">https://www.e-naxos.com/Blog/post/Microsoft-MVVM-Toolkit-Partie-5.aspx</a> (DotBlog, fran&#xE7;ais)</li>
418
</ul>
419
<p>Un exemple de code tir&#xE9; de l&apos;application <code>SicpaExpe</code> :</p>
420
<p>Dans l&apos;impl&#xE9;mentation du <code>ConnexionService</code> :</p>
421
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">ConnexionService</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">INotifyPropertyChanged</span><span class="token punctuation">,</span> <span class="token class-name">IRecipient<span class="token punctuation">&lt;</span>ConnectionSuccessMessage<span class="token punctuation">&gt;</span></span></span>
422
<span class="token punctuation">{</span>
423
    <span class="token comment">// ...</span>
424
    <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task</span> <span class="token function">SetIsConnected</span><span class="token punctuation">(</span><span class="token class-name">ConnectivityChangedEventArgs</span> e <span class="token punctuation">)</span>
425
    <span class="token punctuation">{</span>
426
        <span class="token class-name"><span class="token keyword keyword-bool">bool</span></span> internetAccess <span class="token operator">=</span> e<span class="token punctuation">.</span>NetworkAccess <span class="token operator">==</span> NetworkAccess<span class="token punctuation">.</span>Internet<span class="token punctuation">;</span>
427
        
428
        <span class="token comment">// Test de l&apos;acc&#xE8;s a la BDD wi-fi</span>
429
        <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>internetAccess<span class="token punctuation">)</span>
430
        <span class="token punctuation">{</span>
431
            <span class="token keyword keyword-try">try</span>
432
            <span class="token punctuation">{</span>
433
                <span class="token keyword keyword-await">await</span> Task<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> 
434
                        IsReseauLocal <span class="token operator">=</span> 
435
                            <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Ping</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Send</span><span class="token punctuation">(</span>settingsService<span class="token punctuation">.</span>ServerInfo<span class="token punctuation">.</span>Address<span class="token punctuation">)</span><span class="token punctuation">.</span>Status <span class="token operator">==</span> IPStatus<span class="token punctuation">.</span>Success
436
                    <span class="token punctuation">)</span><span class="token punctuation">;</span>
437
            <span class="token punctuation">}</span>
438
            <span class="token comment">// Cas ou VPN : une exception peut &#xEA;tre lev&#xE9;e par le ping</span>
439
            <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">)</span>
440
            <span class="token punctuation">{</span>
441
                IsReseauLocal <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
442
            <span class="token punctuation">}</span>
443
        <span class="token punctuation">}</span> 
444
        <span class="token keyword keyword-else">else</span>
445
        <span class="token punctuation">{</span>
446
            IsReseauLocal <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
447
        <span class="token punctuation">}</span>
448
        <span class="token comment">// Envoi d&apos;un message que la connexion a chang&#xE9;</span>
449
        WeakReferenceMessenger<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">Send</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ConnectionChangedMessage</span><span class="token punctuation">(</span>IsReseauLocal<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
450
    <span class="token punctuation">}</span>
451

    
452
    <span class="token keyword keyword-public">public</span> <span class="token function">ConnexionService</span><span class="token punctuation">(</span><span class="token range operator">..</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
453
    <span class="token punctuation">{</span>
454
        <span class="token comment">// ...</span>
455
        Connectivity<span class="token punctuation">.</span>ConnectivityChanged <span class="token operator">+=</span> Connectivity_ConnectivityChanged<span class="token punctuation">;</span>
456
        WeakReferenceMessenger<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">Register</span><span class="token punctuation">(</span><span class="token keyword keyword-this">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
457
    <span class="token punctuation">}</span>
458

    
459
    <span class="token comment">// ...</span>
460
<span class="token punctuation">}</span>
461
</pre><p>L&apos;application tente ensuite de se reconnecter &#xE0; la base de donn&#xE9;es du serveur, et si c&apos;est le cas, un message <code>ConnectionSuccessMessage</code> est &#xE9;mis :</p>
462
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">ServerDAO</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IRecipient<span class="token punctuation">&lt;</span>ConnectionChangedMessage<span class="token punctuation">&gt;</span></span></span>
463
<span class="token punctuation">{</span>
464
    <span class="token comment">// ... </span>
465

    
466
    <span class="token keyword keyword-public">public</span> <span class="token function">ServerDAO</span><span class="token punctuation">(</span><span class="token range operator">..</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
467
    <span class="token punctuation">{</span>
468
        <span class="token comment">// ...</span>
469
        WeakReferenceMessenger<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">RegisterAll</span><span class="token punctuation">(</span><span class="token keyword keyword-this">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
470
    <span class="token punctuation">}</span>
471

    
472
    <span class="token comment">// ...</span>
473

    
474
    <span class="token comment">// Fonction d&#xE9;clench&#xE9;e &#xE0; la reception du message ConnectionChangedMessage</span>
475
    <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-void">void</span></span> <span class="token function">Receive</span><span class="token punctuation">(</span><span class="token class-name">ConnectionChangedMessage</span> message<span class="token punctuation">)</span>
476
    <span class="token punctuation">{</span>
477

    
478
        <span class="token comment">// On se reconnecte</span>
479
        <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>message<span class="token punctuation">.</span>Value<span class="token punctuation">)</span>
480
        <span class="token punctuation">{</span>
481
            loadingIndicatorService<span class="token punctuation">.</span>LoadingMessage <span class="token operator">=</span> <span class="token string">&quot;Tentative de connexion &#xE0; &quot;</span> <span class="token operator">+</span> settingsService<span class="token punctuation">.</span>ServerInfo<span class="token punctuation">.</span>Address<span class="token punctuation">;</span>
482
            <span class="token function">OpenConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
483
        <span class="token punctuation">}</span>
484
        <span class="token comment">// On perd la connexion &#xE0; la base</span>
485
        <span class="token keyword keyword-else">else</span>
486
        <span class="token punctuation">{</span>
487
            loadingIndicatorService<span class="token punctuation">.</span>LoadingMessage <span class="token operator">=</span> <span class="token string">&quot;Passage en mode hors ligne...&quot;</span><span class="token punctuation">;</span>
488
            <span class="token comment">// On ferme la connexion a la base pour &#xE9;viter de timeout.</span>
489
            <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>connection <span class="token keyword keyword-is">is</span> <span class="token keyword keyword-not">not</span> <span class="token keyword keyword-null">null</span> 
490
                <span class="token operator">&amp;&amp;</span> connection<span class="token punctuation">.</span>State <span class="token operator">==</span> System<span class="token punctuation">.</span>Data<span class="token punctuation">.</span>ConnectionState<span class="token punctuation">.</span>Open<span class="token punctuation">)</span>
491
                connection<span class="token punctuation">.</span><span class="token function">CloseAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
492
        <span class="token punctuation">}</span>
493
    <span class="token punctuation">}</span>
494

    
495
    <span class="token comment">// Fonction qui sert &#xE0; l&apos;ouverture de la connexion &#xE0; la base MySQL du serveur</span>
496
    <span class="token comment">// Envoi un message ConnectionSuccessMessage si la connexion &#xE0; r&#xE9;ussi ou non</span>
497
    <span class="token keyword keyword-private">private</span> <span class="token return-type class-name"><span class="token keyword keyword-void">void</span></span> <span class="token function">OpenConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
498
    <span class="token punctuation">{</span>
499
        <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>connService<span class="token punctuation">.</span>IsReseauLocal<span class="token punctuation">)</span>
500
        <span class="token punctuation">{</span>
501
            <span class="token class-name">MySqlConnectionStringBuilder</span> builder <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
502
            <span class="token punctuation">{</span>
503
                <span class="token comment">// Les donn&#xE9;es de connexion sont stock&#xE9;es dans le SettingsService</span>
504
                Server <span class="token operator">=</span> settingsService<span class="token punctuation">.</span>ServerInfo<span class="token punctuation">.</span>Address<span class="token punctuation">,</span>
505
                Database <span class="token operator">=</span> <span class="token string">&quot;sidexwifi_test&quot;</span><span class="token punctuation">,</span>
506
                UserID <span class="token operator">=</span> settingsService<span class="token punctuation">.</span>ServerInfo<span class="token punctuation">.</span>Username<span class="token punctuation">,</span>
507
                Password <span class="token operator">=</span> settingsService<span class="token punctuation">.</span>ServerInfo<span class="token punctuation">.</span>Password
508
            <span class="token punctuation">}</span><span class="token punctuation">;</span> 
509
            connection <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span>builder<span class="token punctuation">.</span>ConnectionString<span class="token punctuation">)</span><span class="token punctuation">;</span>
510

    
511
            <span class="token keyword keyword-try">try</span>
512
            <span class="token punctuation">{</span>
513
                connection<span class="token punctuation">.</span><span class="token function">Open</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
514
                WeakReferenceMessenger<span class="token punctuation">.</span>Default<span class="token punctuation">.</span>
515
                    <span class="token function">Send</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ConnectionSuccessMessage</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
516
            <span class="token punctuation">}</span>
517
            <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">)</span>
518
            <span class="token punctuation">{</span>
519
                WeakReferenceMessenger<span class="token punctuation">.</span>Default<span class="token punctuation">.</span>
520
                    <span class="token function">Send</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ConnectionSuccessMessage</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
521
            <span class="token punctuation">}</span>
522
        <span class="token punctuation">}</span>
523
    <span class="token punctuation">}</span>
524
<span class="token punctuation">}</span>
525

    
526
</pre><p>Reception du message <code>ConnectionSuccessMessage</code> par le Service <code>DataSenderService</code> :</p>
527
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">DataSenderService</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IRecipient<span class="token punctuation">&lt;</span>ConnectionSuccessMessage<span class="token punctuation">&gt;</span></span></span>
528
<span class="token punctuation">{</span>
529

    
530
    <span class="token comment">// ...</span>
531
    <span class="token comment">// Fonction d&#xE9;clench&#xE9;e &#xE0; la reception du message ConnectionSuccessMessage</span>
532
    <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-void">void</span></span> <span class="token function">Receive</span><span class="token punctuation">(</span><span class="token class-name">ConnectionSuccessMessage</span> message<span class="token punctuation">)</span>
533
    <span class="token punctuation">{</span>
534
        <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>message<span class="token punctuation">.</span>Value<span class="token punctuation">)</span>
535
            <span class="token comment">// Fonction de synchronisation </span>
536
            <span class="token comment">// NB: la fonction Await() vient de la librairie Prism.Core</span>
537
            <span class="token comment">//  --&gt; permet d&apos;appeler des fonctions asynchrones dans des proc&#xE9;dures synchrones</span>
538
            <span class="token function">SyncResultsAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
539
    <span class="token punctuation">}</span>
540
<span class="token punctuation">}</span>
541
</pre><p>Dans l&apos;application <code>SicpaExpe</code> la synchronisation est &#xE9;galement faite &#xE0; chaque envoi de donn&#xE9;e en ligne, car plusieurs utilisateurs peuvent &#xEA;tre en cours d&apos;utilisation et il est &#xE9;ssentiel que la synchronisation soit faite le plus souvent possible. De plus, le serveur &#xE9;tant heberg&#xE9; sur le r&#xE9;seau local, les interruptions de connexions sont plus rare qu&apos;une connexion passant par des <strong>WebServices</strong>, sur un serveur distant, par exemple.</p>
542
<p>Dans l&apos;application <code>SIPMobile</code>, cette synchronisation n&apos;est pas aussi cruciale et la connexion aux WebServices &#xE9;tant quelquefois al&#xE9;atoire dans les UEs. Le syst&#xE8;me que j&apos;ai adopt&#xE9; est un syst&#xE8;me de synchronisation manuelle, avec lequel l&apos;utilisateur choisi d&apos;envoyer ses donn&#xE9;es en attente d&apos;envoi, et de re-t&#xE9;l&#xE9;charger les donn&#xE9;es de la base, dans un onglet sp&#xE9;cial nomm&#xE9; &quot;Synchronisation&quot;.</p>
543
<p>La gestion des modes en ligne et hors ligne est sp&#xE9;cifique &#xE0; l&apos;utilisation des applications, ainsi que du type de BDD distante avec laquelle l&apos;application int&#xE9;ragit. Plusieurs impl&#xE9;mentations sont possibles et je recommande de se fixer des <em>r&#xE8;gles</em> &#xE0; l&apos;avance pour rester coh&#xE9;rent dans le stockage des donn&#xE9;es, et &#xE9;viter la d&#xE9;synchronisation.</p>
544
<h2 class="mume-header" id="appel-aux-ws-rest">Appel aux WS Rest</h2>
545

    
546
<p>L&apos;application <code>SIPMobile</code> a &#xE9;t&#xE9; cr&#xE9;&#xE9;e comme projet de migration de l&apos;application SIPXami, d&#xE9;velopp&#xE9;e en <em>Xamarin</em>, vers la technologie MAUI. Nous avons profit&#xE9; de cette migration pour remplacer l&apos;utilisation des WS <code>SOAP + XML</code> par l&apos;utilisation des WS <code>REST + JSON</code>.</p>
547
<p>Pour faire les diff&#xE9;rents appels aux WS, j&apos;ai d&#xE9;cid&#xE9; d&apos;utiliser la librairie <code>RestSharp</code>, soutenue par la fondation .NET :</p>
548
<ul>
549
<li><a href="https://restsharp.dev/intro.html#introduction">https://restsharp.dev/intro.html#introduction</a> (Documentation RestSharp)</li>
550
<li><a href="https://dotnetfoundation.org/">https://dotnetfoundation.org/</a> (Site de la fondation .NET)</li>
551
</ul>
552
<h3 class="mume-header" id="instanciation">Instanciation</h3>
553

    
554
<p>Pour utiliser la librairie, il faut tout d&apos;abord instancier un objet <code>RestClient</code> de la fa&#xE7;on suivante :</p>
555
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">ServerDAO</span>
556
<span class="token punctuation">{</span>
557
    
558
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">RestClient</span> client<span class="token punctuation">;</span>
559
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name"><span class="token keyword keyword-string">string</span></span> baseUrl <span class="token operator">=</span> <span class="token comment">//...</span>
560
    <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">JsonSerializerOptions</span> serializerOptions<span class="token punctuation">;</span>
561
    
562
    <span class="token keyword keyword-public">public</span> <span class="token function">ServerDAO</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
563
    <span class="token punctuation">{</span>
564
        <span class="token comment">// baseUrl est l&apos;url de base du WS Rest</span>
565
        client <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">RestClientOptions</span><span class="token punctuation">(</span>baseUrl<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
566

    
567
        <span class="token comment">// options qui servent pour cr&#xE9;er &quot;parser&quot; les objets</span>
568
        <span class="token comment">// arrivants/sortants et s&#xE9;rialis&#xE9;s en JSON</span>
569
        serializerOptions <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
570
        <span class="token punctuation">{</span>
571
            PropertyNamingPolicy <span class="token operator">=</span> JsonNamingPolicy<span class="token punctuation">.</span>CamelCase<span class="token punctuation">,</span>
572
            WriteIndented <span class="token operator">=</span> <span class="token boolean">true</span>
573
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
574
    <span class="token punctuation">}</span>
575
<span class="token punctuation">}</span>
576
</pre><p>Pour plus d&apos;infos sur le <code>JSONSerializerOptions</code> :<br>
577
<a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/configure-options?pivots=dotnet-7-0">https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/configure-options?pivots=dotnet-7-0</a></p>
578
<h3 class="mume-header" id="r%C3%A9cup%C3%A9rer-des-donn%C3%A9es">R&#xE9;cup&#xE9;rer des donn&#xE9;es</h3>
579

    
580
<p>Pour r&#xE9;cup&#xE9;rer les donn&#xE9;es, il suffit de cr&#xE9;er un objet <code>RestRequest</code> avec en options le <em>endpoint</em> de l&apos;API REST que l&apos;on souhaite attaquer. Cet objet est ensuite utilis&#xE9; dans la fonction <code>GetAsync</code> propos&#xE9; par notre objet <code>client</code> (Type: <code>RestClient</code>)</p>
581
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>List<span class="token punctuation">&lt;</span>Categorie<span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">GetCategories</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
582
<span class="token punctuation">{</span>
583
    <span class="token comment">// Attention &#xE0; l&apos;URL qui est sensible aux majuscules !!</span>
584
    <span class="token class-name">RestRequest</span> restRequest <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token string">&quot;categorieService/listeCategories&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
585
    <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-await">await</span> client<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>List<span class="token punctuation">&lt;</span>Categorie<span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span>restRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
586
<span class="token punctuation">}</span>
587
</pre><p>Sauf ajout d&apos;annotations pour la d&#xE9;s&#xE9;rialisation ou &quot;<em>parsing</em>&quot; des objets en Json, la conversion des objets se fait en fonction de leur nom de propri&#xE9;t&#xE9;s, et sans contraintes li&#xE9;e aux majuscules. Par exemple pour un objet <code>Categorie</code> venant de l&apos;API suivant :</p>
588
<pre data-role="codeBlock" data-info="java" class="language-java"><span class="token class-name">Categorie</span>
589
<span class="token punctuation">{</span>
590
    idCategorie     <span class="token function">integer</span><span class="token punctuation">(</span>$int32<span class="token punctuation">)</span>
591
    nomCategorie    string
592
<span class="token punctuation">}</span> 
593
</pre><p>L&apos;objet correspondant dans l&apos;application <code>SIPMobile</code> est :</p>
594
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">Categorie</span>
595
<span class="token punctuation">{</span>
596
    <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-int">int</span></span> IDCategorie <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
597
    <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> NomCategorie <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
598
<span class="token punctuation">}</span>
599
</pre><p>Et ainsi le <em>parsing</em> et donc l&apos;affectation des valeurs se font automatiquement.</p>
600
<p>Exemple d&apos;une fonction avec ajout d&apos;un argument <code>uniteID</code>:</p>
601
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>List<span class="token punctuation">&lt;</span>Zone<span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">GetZonesFromUnite</span><span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-int">int</span></span> uniteID<span class="token punctuation">)</span>
602
<span class="token punctuation">{</span>
603
    <span class="token class-name">RestRequest</span> restRequest <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token string">&quot;zoneService/listeZonesByUnite?idUnite=&quot;</span> <span class="token operator">+</span> uniteID<span class="token punctuation">)</span><span class="token punctuation">;</span>
604
    <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-await">await</span> client<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">GetAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>List<span class="token punctuation">&lt;</span>Zone<span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span>restRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
605
<span class="token punctuation">}</span>
606
</pre><h3 class="mume-header" id="envoyer-des-donn%C3%A9es">Envoyer des donn&#xE9;es</h3>
607

    
608
<p>L&apos;envoi des donn&#xE9;es est un petit plus complexe, car cela demande de cr&#xE9;er une m&#xE9;thode POST et de s&#xE9;rialiser en JSON les objets &#xE0; envoyer.</p>
609
<p>Dans l&apos;application <code>SIPMobile</code>, l&apos;envoi de donn&#xE9;es se fait dans l&apos;url de la requ&#xEA;te, ce qui donne le code suivant pour l&apos;envoi de plusieurs objets <code>Mouvement</code> (une liste), par exemple.</p>
610
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span><span class="token keyword keyword-bool">bool</span><span class="token punctuation">&gt;</span></span> <span class="token function">SaveMouvementList</span><span class="token punctuation">(</span><span class="token class-name">List<span class="token punctuation">&lt;</span>Mouvement<span class="token punctuation">&gt;</span></span> mouvementList<span class="token punctuation">)</span>
611
<span class="token punctuation">{</span>
612
    <span class="token class-name">RestRequest</span> restRequest <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token string">&quot;mouvementService/insertMouvementsTotalByIndividu&quot;</span><span class="token punctuation">,</span> Method<span class="token punctuation">.</span>Post<span class="token punctuation">)</span><span class="token punctuation">;</span>
613
    <span class="token comment">// Serialisation au format JSON du mouvement</span>
614
    <span class="token class-name"><span class="token keyword keyword-string">string</span></span> mouvementsJson <span class="token operator">=</span> JsonSerializer<span class="token punctuation">.</span><span class="token function">Serialize</span><span class="token punctuation">(</span>mouvementList<span class="token punctuation">,</span> serializerOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
615
    
616
    <span class="token comment">// Ajout de l&apos;objet s&#xE9;rialis&#xE9; en argument </span>
617
    <span class="token comment">// NB: les noms d&apos;arguments soivent respecter les majuscules!</span>
618
    restRequest<span class="token punctuation">.</span>AddParameter
619
        <span class="token punctuation">(</span><span class="token string">&quot;mouvementsJson&quot;</span><span class="token punctuation">,</span> <span class="token comment">// le nom du param&#xE8;tre (attention &#xE0; la case!)</span>
620
        mouvementsJson<span class="token punctuation">,</span> <span class="token comment">// l&apos;objet s&#xE9;rialis&#xE9; en json</span>
621
        ParameterType<span class="token punctuation">.</span>QueryString <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// le param&#xE8;tre est dans l&apos;url (=query)</span>
622
    
623
    <span class="token keyword keyword-try">try</span>
624
    <span class="token punctuation">{</span>
625
        <span class="token comment">// Envoi de la requ&#xEA;te</span>
626
        <span class="token keyword keyword-await">await</span> client<span class="token punctuation">.</span><span class="token function">PostAsync</span><span class="token punctuation">(</span>restRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
627
        <span class="token keyword keyword-return">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
628
    <span class="token punctuation">}</span>
629
    <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">)</span>
630
    <span class="token punctuation">{</span>
631
        <span class="token keyword keyword-return">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
632
    <span class="token punctuation">}</span>
633
<span class="token punctuation">}</span>
634
</pre><p>&#xC0; noter l&apos;utilisation de l&apos;argument <code>ParameterType.QueryString</code> dans la fonction <code>AddParameter</code> pour r&#xE9;pondre &#xE0; la n&#xE9;cessit&#xE9; d&apos;avoir les arguments dans l&apos;url de la requ&#xEA;te. Sans ajout de ce param&#xE8;tre, les objets &#xE0; envoyer sont ajout&#xE9;s au champ <code>&lt;body&gt;</code> de la requ&#xEA;te.</p>
635
<p>NB: sur SIPMobile, j&apos;ai recontr&#xE9; un probl&#xE8;me ou le format <code>DateTime</code> &#xE9;tait donn&#xE9; avec le fuseaux horaires (heure d&apos;&#xE9;t&#xE9; = +2h) et la s&#xE9;rialisation en JSON comprenait ce param&#xE8;tre. Lors de l&apos;enregistrement sur le serveur, la date &#xE9;tait convertie avec 2h de moins...<br>
636
Pour contourner le probl&#xE8;me je cr&#xE9;&#xE9; les objets <code>Datetime</code> de la fa&#xE7;on suivante :</p>
637
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token comment">// Probl&#xE8;me avec fuseaux horaire :</span>
638
<span class="token class-name">DateTime</span> dateChangement <span class="token operator">=</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">;</span>
639
<span class="token comment">// Sans le fuseaux horaire :</span>
640
<span class="token class-name">DateTime</span> dateChangement <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span>DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">.</span>Ticks<span class="token punctuation">,</span> DateTimeKind<span class="token punctuation">.</span>Utc<span class="token punctuation">)</span><span class="token punctuation">;</span>
641
</pre><h2 class="mume-header" id="permissions-sp%C3%A9cifiques-fichiers-externes-android">Permissions sp&#xE9;cifiques fichiers externes Android</h2>
642

    
643
<p>Pour certaines applications, il peut &#xEA;tre indispensable d&apos;acc&#xE9;der aux fichiers &quot;externes&quot; de l&apos;appareil, c&apos;est-&#xE0;-dire les fichiers qui ne sont pas propre &#xE0; l&apos;application et donc communs &#xE0; toutes les applications. Parmi ces fichiers, on peut par exemple trouver les fichiers issus des t&#xE9;l&#xE9;chargements.<br>
644
Avant Android 11, leur acc&#xE8;s demandaient la simple addition au Manifest et acceptation des permissions <code>StorageRead</code> et <code>StorageWrite</code>, mais depuis, c&apos;est devenu un peu plus compliqu&#xE9;...</p>
645
<p>Plus d&apos;info sur <a href="https://developer.android.com/training/data-storage?hl=fr#permissions">https://developer.android.com/training/data-storage?hl=fr#permissions</a> (Documentation Android officielle).</p>
646
<p>M&#xE9;thode sous Android inf&#xE9;rieur &#xE0; 11 :<br>
647
D&#xE9;clarer les permissions dans le Manifest Android : Nom_du_projet &gt; Platforms &gt; Android &gt; AndroidManifest.xml &gt; Clique-droit &gt; Ouvrir Avec &gt; Editeur XML.</p>
648
<pre data-role="codeBlock" data-info="xml" class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>manifest</span> <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
649
    <span class="token comment">&lt;!-- ... --&gt;</span>
650
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>uses-permission</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>android.permission.READ_EXTERNAL_STORAGE<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
651
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>uses-permission</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>android.permission.WRITE_EXTERNAL_STORAGE<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
652
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>manifest</span><span class="token punctuation">&gt;</span></span>
653
</pre><p>Puis au lancement de l&apos;application, v&#xE9;rifier si les permissions sont allou&#xE9;es :</p>
654
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">RequestAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Permissions<span class="token punctuation">.</span>StorageRead<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
655
<span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">RequestAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Permissions<span class="token punctuation">.</span>StorageWrite<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
656
</pre><p>Sur les version d&apos;android sup&#xE9;rieures ou &#xE9;gales &#xE0; 11, une seule permissions doit &#xEA;tre ajout&#xE9;e au Manifest:</p>
657
<pre data-role="codeBlock" data-info="xml" class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>manifest</span> <span class="token attr-name">...</span><span class="token punctuation">&gt;</span></span>
658
    <span class="token comment">&lt;!-- ... --&gt;</span>   
659
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>uses-permission</span> <span class="token attr-name"><span class="token namespace">android:</span>name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>android.permission.MANAGE_EXTERNAL_STORAGE<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
660
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>manifest</span><span class="token punctuation">&gt;</span></span>
661
</pre><p>Mais en outre, l&apos;utilisateur doit cocher une demande de permissions dans les param&#xE8;tres du syst&#xE8;me qui autorise l&apos;application &#xE0; acc&#xE9;der &#xE0; tous les fichiers de l&apos;appareil.<br>
662
Pour cela, cr&#xE9;er une classe que l&apos;on peut nommer <code>ManageStoragePerm</code>, par exemple, et qui h&#xE9;rite de <code>Permissions.BasePlatformPermission</code>:</p>
663
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">ManageStoragePerm</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">Permissions<span class="token punctuation">.</span>BasePlatformPermission</span></span>
664
    <span class="token punctuation">{</span>
665
<span class="token preprocessor property">#<span class="token directive keyword">if</span> ANDROID</span>
666
        <span class="token comment">// Fonction qui permet de v&#xE9;rifier si la permission a &#xE9;t&#xE9; allou&#xE9;e</span>
667
        <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-override">override</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>PermissionStatus<span class="token punctuation">&gt;</span></span> <span class="token function">CheckStatusAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
668
        <span class="token punctuation">{</span>
669
            <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>Android<span class="token punctuation">.</span>OS<span class="token punctuation">.</span>Environment<span class="token punctuation">.</span>IsExternalStorageManager<span class="token punctuation">)</span>
670
            <span class="token punctuation">{</span>
671
                <span class="token keyword keyword-return">return</span> Task<span class="token punctuation">.</span><span class="token function">FromResult</span><span class="token punctuation">(</span>PermissionStatus<span class="token punctuation">.</span>Granted<span class="token punctuation">)</span><span class="token punctuation">;</span>
672
            <span class="token punctuation">}</span> <span class="token keyword keyword-else">else</span>
673
            <span class="token punctuation">{</span>
674
                <span class="token keyword keyword-return">return</span> Task<span class="token punctuation">.</span><span class="token function">FromResult</span><span class="token punctuation">(</span>PermissionStatus<span class="token punctuation">.</span>Unknown<span class="token punctuation">)</span><span class="token punctuation">;</span>
675
            <span class="token punctuation">}</span>
676
        <span class="token punctuation">}</span>
677

    
678
        <span class="token comment">// Fonction qui permet d&apos;ouvrir la fen&#xEA;tre dans les param&#xE8;tres de l&apos;appareil</span>
679
        <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-override">override</span> <span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>PermissionStatus<span class="token punctuation">&gt;</span></span> <span class="token function">RequestAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
680
        <span class="token punctuation">{</span>
681
            <span class="token keyword keyword-try">try</span>
682
            <span class="token punctuation">{</span>
683
                <span class="token class-name">Android<span class="token punctuation">.</span>Net<span class="token punctuation">.</span>Uri</span> uri <span class="token operator">=</span> Android<span class="token punctuation">.</span>Net<span class="token punctuation">.</span>Uri<span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span><span class="token string">&quot;package:&quot;</span> <span class="token operator">+</span> AppInfo<span class="token punctuation">.</span>PackageName<span class="token punctuation">)</span><span class="token punctuation">;</span>
684
                <span class="token class-name">Android<span class="token punctuation">.</span>Content<span class="token punctuation">.</span>Intent</span> intent <span class="token operator">=</span> 
685
                    <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span>Android<span class="token punctuation">.</span>Provider<span class="token punctuation">.</span>Settings<span class="token punctuation">.</span>ActionManageAppAllFilesAccessPermission<span class="token punctuation">,</span> uri<span class="token punctuation">)</span><span class="token punctuation">;</span>
686
                Platform<span class="token punctuation">.</span>CurrentActivity<span class="token punctuation">.</span><span class="token function">StartActivity</span><span class="token punctuation">(</span>intent<span class="token punctuation">)</span><span class="token punctuation">;</span>
687
            <span class="token punctuation">}</span> 
688
            <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">)</span>
689
            <span class="token punctuation">{</span>
690
                <span class="token class-name">Android<span class="token punctuation">.</span>Content<span class="token punctuation">.</span>Intent</span> intent <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
691
                intent<span class="token punctuation">.</span><span class="token function">SetAction</span><span class="token punctuation">(</span>Android<span class="token punctuation">.</span>Provider<span class="token punctuation">.</span>Settings<span class="token punctuation">.</span>ActionManageAllFilesAccessPermission<span class="token punctuation">)</span><span class="token punctuation">;</span>
692
                Platform<span class="token punctuation">.</span>CurrentActivity<span class="token punctuation">.</span><span class="token function">StartActivity</span><span class="token punctuation">(</span>intent<span class="token punctuation">)</span><span class="token punctuation">;</span>
693
            <span class="token punctuation">}</span>
694
            <span class="token keyword keyword-return">return</span> Task<span class="token punctuation">.</span><span class="token function">FromResult</span><span class="token punctuation">(</span>PermissionStatus<span class="token punctuation">.</span>Unknown<span class="token punctuation">)</span><span class="token punctuation">;</span>
695
        <span class="token punctuation">}</span>
696
<span class="token preprocessor property">#<span class="token directive keyword">endif</span></span>
697

    
698
    <span class="token punctuation">}</span>
699
</pre><p>Exemple de code de v&#xE9;rification des permissions pour la gestion du stockage externe sur l&apos;application <code>SIPMobile</code>, utilis&#xE9;e sur des appareils cibles dont la version Android peut aller de 7.1 &#xE0; 13 (&#xE0; l&apos;heure de la r&#xE9;daction de ce document) :</p>
700
<pre data-role="codeBlock" data-info="csharp" class="language-csharp"><span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>DeviceInfo<span class="token punctuation">.</span>Version<span class="token punctuation">.</span>Major <span class="token operator">&gt;=</span> <span class="token number">11</span><span class="token punctuation">)</span>
701
<span class="token punctuation">{</span>
702
    <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">CheckStatusAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ManageStoragePerm<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> PermissionStatus<span class="token punctuation">.</span>Unknown<span class="token punctuation">)</span>
703
    <span class="token punctuation">{</span>
704
        <span class="token keyword keyword-await">await</span> Application<span class="token punctuation">.</span>Current<span class="token punctuation">.</span>MainPage
705
        <span class="token punctuation">.</span><span class="token function">DisplayAlert</span><span class="token punctuation">(</span>
706
            <span class="token string">&quot;Information&quot;</span><span class="token punctuation">,</span> 
707
            <span class="token string">&quot;Veuillez cocher l&apos;option d&apos;acc&#xE8;s aux fichier dans la fen&#xEA;tre suivante.&quot;</span><span class="token punctuation">,</span> 
708
            <span class="token string">&quot;Suivant&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
709
        <span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">RequestAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ManageStoragePerm<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
710
    <span class="token punctuation">}</span>
711

    
712
    <span class="token comment">// On ne &quot;catch&quot; pas le retour de l&apos;activit&#xE9; donc on attend avec une boucle de 15 secondes</span>
713
    <span class="token class-name"><span class="token keyword keyword-int">int</span></span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
714
    <span class="token keyword keyword-while">while</span> <span class="token punctuation">(</span><span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">CheckStatusAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ManageStoragePerm<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> PermissionStatus<span class="token punctuation">.</span>Unknown <span class="token operator">&amp;&amp;</span> count <span class="token operator">&lt;</span> <span class="token number">15</span><span class="token punctuation">)</span>
715
    <span class="token punctuation">{</span>
716
        loadingIndicatorService<span class="token punctuation">.</span>Message <span class="token operator">=</span> <span class="token string">&quot;Attente des autorisations...&quot;</span><span class="token punctuation">;</span>
717
        <span class="token keyword keyword-await">await</span> Task<span class="token punctuation">.</span><span class="token function">Delay</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
718
        count<span class="token operator">++</span><span class="token punctuation">;</span>
719
    <span class="token punctuation">}</span>
720

    
721
    <span class="token comment">// Si &#xE0; la fin des 15 secondes, on a toujours pas l&apos;autorisation</span>
722
    <span class="token comment">// Demande &#xE0; l&apos;utilisateur de relancer l&apos;appli</span>
723
    <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">CheckStatusAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>ManageStoragePerm<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> PermissionStatus<span class="token punctuation">.</span>Granted<span class="token punctuation">)</span> 
724
    <span class="token punctuation">{</span>
725
        <span class="token keyword keyword-await">await</span> Application<span class="token punctuation">.</span>Current<span class="token punctuation">.</span>MainPage
726
        <span class="token punctuation">.</span><span class="token function">DisplayAlert</span><span class="token punctuation">(</span>
727
            <span class="token string">&quot;Erreur&quot;</span><span class="token punctuation">,</span> 
728
            <span class="token string">&quot;L&apos;autorisation d&apos;acc&#xE8;s aux fichiers est requise pour le bon fonctionnement de l&apos;application. Relancez l&apos;application.&quot;</span><span class="token punctuation">,</span> 
729
            <span class="token string">&quot;OK&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
730
        loadingIndicatorService<span class="token punctuation">.</span>IsBusy <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
731
        <span class="token keyword keyword-return">return</span><span class="token punctuation">;</span>
732
    <span class="token punctuation">}</span>
733
<span class="token punctuation">}</span>
734
<span class="token comment">// Version en dessous de 11</span>
735
<span class="token keyword keyword-else">else</span>
736
<span class="token punctuation">{</span>
737
    <span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">RequestAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Permissions<span class="token punctuation">.</span>StorageRead<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
738
    <span class="token keyword keyword-await">await</span> Permissions<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">RequestAsync</span><span class="token generic class-name"><span class="token punctuation">&lt;</span>Permissions<span class="token punctuation">.</span>StorageWrite<span class="token punctuation">&gt;</span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
739
<span class="token punctuation">}</span>
740
</pre><p>On y voit l&apos;appel &#xE0; 3 reprises des fonctions de notre classe <code>ManageStoragePerms</code>. La fen&#xEA;tre des param&#xE8;tres ou il est demand&#xE9; de cocher une option ressemble &#xE0; la capture d&apos;&#xE9;cran suivante sur un appareil avec Android 12.</p>
741
<p><img src="capture_permissions.png" alt="capture permission"></p>
742

    
743
      </div>
744
      
745
      
746
    
747
    
748
    
749
    
750
    
751
    
752
    
753
    
754
  
755
    </body></html>