Skip to content

Commit 5304ad3

Browse files
committed
Implement Query By Example
Updated the GenericConsumer to add a new Retrieve method that accepts an "example" object. Updated the Get method of the GenericController to handle a payload when a method override is requested. Updated the demo AU Provider configuration to manage redirection when a method override is requested. Updated the demo AU Consumer with an example call that uses the new Retrieve method.
1 parent 5c35776 commit 5304ad3

25 files changed

Lines changed: 237 additions & 96 deletions

File tree

Code/Sif3Framework/Sif.Framework.EnvironmentProvider/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@
3131
//
3232
// You can specify all the values or you can default the Revision and Build Numbers
3333
// by using the '*' as shown below:
34-
[assembly: AssemblyVersion("0.19.0.0")]
35-
[assembly: AssemblyFileVersion("0.19.0.0")]
34+
[assembly: AssemblyVersion("0.20.0.0")]
35+
[assembly: AssemblyFileVersion("0.20.0.0")]

Code/Sif3Framework/Sif.Framework.Tests/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("0.19.0.0")]
36-
[assembly: AssemblyFileVersion("0.19.0.0")]
35+
[assembly: AssemblyVersion("0.20.0.0")]
36+
[assembly: AssemblyFileVersion("0.20.0.0")]

Code/Sif3Framework/Sif.Framework/Consumer/GenericConsumer.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,25 @@ public virtual ICollection<T> Retrieve()
190190
return result;
191191
}
192192

193+
/// <summary>
194+
/// <see cref="Sif.Framework.Consumer.IGenericConsumer{T,PK}.Retrieve(T)">Retrieve</see>
195+
/// </summary>
196+
public virtual ICollection<T> Retrieve(T obj)
197+
{
198+
199+
if (!registrationService.Registered)
200+
{
201+
throw new InvalidOperationException("Consumer has not registered.");
202+
}
203+
204+
string url = EnvironmentUtils.ParseServiceUrl(environmentTemplate) + "/" + TypeName + "s";
205+
string body = SerialiserFactory.GetXmlSerialiser<T>().Serialise(obj);
206+
string xml = HttpUtils.PostRequest(url, registrationService.AuthorisationToken, body, "GET");
207+
if (log.IsDebugEnabled) log.Debug("XML from POST request ...");
208+
if (log.IsDebugEnabled) log.Debug(xml);
209+
return SerialiserFactory.GetXmlSerialiser<List<T>>(new XmlRootAttribute(TypeName + "s")).Deserialise(xml);
210+
}
211+
193212
/// <summary>
194213
/// <see cref="Sif.Framework.Consumer.IGenericConsumer{T,PK}.Retrieve(System.Int32, System.Int32)">Retrieve</see>
195214
/// </summary>

Code/Sif3Framework/Sif.Framework/Consumer/IGenericConsumer.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ public interface IGenericConsumer<T, PK> where T : IPersistable<PK>
7777
/// <returns></returns>
7878
ICollection<T> Retrieve();
7979

80+
/// <summary>
81+
/// POST /StudentPersonals (X-HTTP-Method-Override: GET)
82+
/// </summary>
83+
/// <param name="obj"></param>
84+
/// <returns></returns>
85+
ICollection<T> Retrieve(T obj);
86+
8087
/// <summary>
8188
/// GET /StudentPersonals
8289
/// </summary>

Code/Sif3Framework/Sif.Framework/Controller/GenericController.cs

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public virtual T Get(PK id)
137137
/// GET api/{controller}
138138
/// </summary>
139139
/// <returns>All objects.</returns>
140-
public virtual List<T> Get()
140+
public virtual List<T> Get(T item)
141141
{
142142

143143
if (!authService.VerifyAuthenticationHeader(Request.Headers.Authorization))
@@ -149,42 +149,6 @@ public virtual List<T> Get()
149149
IEnumerable<String> navigationPageSizeValues;
150150
bool navigationPageFound = Request.Headers.TryGetValues("navigationPage", out navigationPageValues);
151151
bool navigationPageSizeFound = Request.Headers.TryGetValues("navigationPageSize", out navigationPageSizeValues);
152-
int? navigationPage = null;
153-
int? navigationPageSize = null;
154-
155-
if (navigationPageFound)
156-
{
157-
158-
if ((new List<String>(navigationPageValues)).Count == 1)
159-
{
160-
IEnumerator<String> enumerator = navigationPageValues.GetEnumerator();
161-
enumerator.MoveNext();
162-
navigationPage = Int32.Parse(enumerator.Current);
163-
}
164-
else
165-
{
166-
string errorMessage = "The GET request failed for " + typeof(T).Name + " because multiple values were found for the navigationPage request header field.";
167-
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, errorMessage));
168-
}
169-
170-
}
171-
172-
if (navigationPageSizeFound)
173-
{
174-
175-
if ((new List<String>(navigationPageSizeValues)).Count == 1)
176-
{
177-
IEnumerator<String> enumerator = navigationPageSizeValues.GetEnumerator();
178-
enumerator.MoveNext();
179-
navigationPageSize = Int32.Parse(enumerator.Current);
180-
}
181-
else
182-
{
183-
string errorMessage = "The GET request failed for " + typeof(T).Name + " because multiple values were found for the navigationPageSize request header field.";
184-
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, errorMessage));
185-
}
186-
187-
}
188152

189153
if (navigationPageFound && !navigationPageSizeFound)
190154
{
@@ -198,15 +162,48 @@ public virtual List<T> Get()
198162
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, errorMessage));
199163
}
200164

165+
bool methodOverrideFound = Request.Headers.Contains("X-HTTP-Method-Override");
166+
bool payloadFound = (item != null);
201167
List<T> items;
202168

203169
try
204170
{
205171

206172
if (navigationPageFound && navigationPageSizeFound)
207173
{
174+
int? navigationPage = null;
175+
int? navigationPageSize = null;
176+
177+
if ((new List<String>(navigationPageValues)).Count == 1)
178+
{
179+
IEnumerator<String> enumerator = navigationPageValues.GetEnumerator();
180+
enumerator.MoveNext();
181+
navigationPage = Int32.Parse(enumerator.Current);
182+
}
183+
else
184+
{
185+
string errorMessage = "The GET request failed for " + typeof(T).Name + " because multiple values were found for the navigationPage request header field.";
186+
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, errorMessage));
187+
}
188+
189+
if ((new List<String>(navigationPageSizeValues)).Count == 1)
190+
{
191+
IEnumerator<String> enumerator = navigationPageSizeValues.GetEnumerator();
192+
enumerator.MoveNext();
193+
navigationPageSize = Int32.Parse(enumerator.Current);
194+
}
195+
else
196+
{
197+
string errorMessage = "The GET request failed for " + typeof(T).Name + " because multiple values were found for the navigationPageSize request header field.";
198+
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, errorMessage));
199+
}
200+
208201
items = (List<T>)service.Retrieve((int)navigationPage, (int)navigationPageSize);
209202
}
203+
else if (methodOverrideFound && payloadFound)
204+
{
205+
items = (List<T>)service.Retrieve(item);
206+
}
210207
else
211208
{
212209
items = (List<T>)service.Retrieve();

Code/Sif3Framework/Sif.Framework/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("0.19.0.0")]
36-
[assembly: AssemblyFileVersion("0.19.0.0")]
35+
[assembly: AssemblyVersion("0.20.0.0")]
36+
[assembly: AssemblyFileVersion("0.20.0.0")]
3737

3838
// Configure log4net using the .config file
3939
[assembly: log4net.Config.XmlConfigurator(Watch = true)]

Code/Sif3Framework/Sif.Framework/Sif.Framework.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
<Compile Include="Service\Sessions\ConsumerSessionService.cs" />
123123
<Compile Include="Service\Sessions\ProviderSessionService.cs" />
124124
<Compile Include="Utils\EnvironmentUtils.cs" />
125+
<Compile Include="Utils\MethodOverrideHandler.cs" />
125126
<Compile Include="Utils\RegistrationManager.cs" />
126127
<Compile Include="Utils\SessionsManager.cs" />
127128
<Compile Include="Utils\SettingsManager.cs" />

Code/Sif3Framework/Sif.Framework/Utils/HttpUtils.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ enum RequestMethod { DELETE, GET, POST, PUT }
4343
/// <param name="navigationPage"></param>
4444
/// <param name="navigationPageSize"></param>
4545
/// <returns></returns>
46-
private static HttpWebRequest CreateHttpWebRequest(RequestMethod requestMethod, string url, string authorisationToken, int? navigationPage = null, int? navigationPageSize = null)
46+
private static HttpWebRequest CreateHttpWebRequest(RequestMethod requestMethod, string url, string authorisationToken, int? navigationPage = null, int? navigationPageSize = null, string methodOverride = null)
4747
{
4848
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
4949
request.ContentType = "application/xml";
@@ -62,6 +62,11 @@ private static HttpWebRequest CreateHttpWebRequest(RequestMethod requestMethod,
6262
request.Headers.Add("navigationPageSize", navigationPageSize.Value.ToString());
6363
}
6464

65+
if (!String.IsNullOrWhiteSpace(methodOverride))
66+
{
67+
request.Headers.Add("X-HTTP-Method-Override", methodOverride.Trim());
68+
}
69+
6570
return request;
6671
}
6772

@@ -76,7 +81,7 @@ private static HttpWebRequest CreateHttpWebRequest(RequestMethod requestMethod,
7681
/// <returns></returns>
7782
private static string RequestWithoutPayload(RequestMethod requestMethod, string url, string authorisationToken, int? navigationPage = null, int? navigationPageSize = null)
7883
{
79-
HttpWebRequest request = CreateHttpWebRequest(requestMethod, url, authorisationToken, navigationPage, navigationPageSize);
84+
HttpWebRequest request = CreateHttpWebRequest(requestMethod, url, authorisationToken, navigationPage: navigationPage, navigationPageSize: navigationPageSize);
8085

8186
using (WebResponse response = request.GetResponse())
8287
{
@@ -109,9 +114,9 @@ private static string RequestWithoutPayload(RequestMethod requestMethod, string
109114
/// <param name="authorisationToken"></param>
110115
/// <param name="body"></param>
111116
/// <returns></returns>
112-
private static string RequestWithPayload(RequestMethod requestMethod, string url, string authorisationToken, string body)
117+
private static string RequestWithPayload(RequestMethod requestMethod, string url, string authorisationToken, string body, string methodOverride = null)
113118
{
114-
HttpWebRequest request = CreateHttpWebRequest(requestMethod, url, authorisationToken);
119+
HttpWebRequest request = CreateHttpWebRequest(requestMethod, url, authorisationToken, methodOverride: methodOverride);
115120

116121
using (Stream requestStream = request.GetRequestStream())
117122
{
@@ -174,9 +179,9 @@ public static string GetRequest(string url, string authorisationToken, int? navi
174179
/// <param name="authorisationToken"></param>
175180
/// <param name="body"></param>
176181
/// <returns></returns>
177-
public static string PostRequest(string url, string authorisationToken, string body)
182+
public static string PostRequest(string url, string authorisationToken, string body, string methodOverride = null)
178183
{
179-
return RequestWithPayload(RequestMethod.POST, url, authorisationToken, body);
184+
return RequestWithPayload(RequestMethod.POST, url, authorisationToken, body, methodOverride);
180185
}
181186

182187
/// <summary>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2015 Systemic Pty Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using System;
18+
using System.Linq;
19+
using System.Net.Http;
20+
using System.Threading;
21+
using System.Threading.Tasks;
22+
23+
namespace Sif.Framework.Utils
24+
{
25+
26+
/// <summary>
27+
///
28+
/// </summary>
29+
public class MethodOverrideHandler : DelegatingHandler
30+
{
31+
readonly string[] _methods = { "DELETE", "GET" };
32+
const string _header = "X-HTTP-Method-Override";
33+
34+
/// <summary>
35+
///
36+
/// </summary>
37+
/// <param name="request"></param>
38+
/// <param name="cancellationToken"></param>
39+
/// <returns></returns>
40+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
41+
{
42+
43+
// Check for HTTP POST with the X-HTTP-Method-Override header.
44+
if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
45+
{
46+
// Check if the header value is in our methods list.
47+
var method = request.Headers.GetValues(_header).FirstOrDefault();
48+
49+
if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
50+
{
51+
// Change the request method.
52+
request.Method = new HttpMethod(method);
53+
}
54+
55+
}
56+
57+
return base.SendAsync(request, cancellationToken);
58+
}
59+
60+
}
61+
62+
}
63+

Code/Sif3FrameworkDemo/Sif.Framework.Demo.Au.Consumer/ConsumerApp.cs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,17 @@ void RunStudentPersonalConsumer()
6262

6363
try
6464
{
65-
// Retrieve all students.
66-
ICollection<StudentPersonal> students = studentPersonalConsumer.Retrieve();
65+
// Retrieve Bart Simpson.
66+
Name name = new Name { FamilyName = "Simpson", GivenName = "Bart" };
67+
PersonInfo personInfo = new PersonInfo { Name = name };
68+
StudentPersonal studentPersonal = new StudentPersonal { PersonInfo = personInfo };
69+
ICollection<StudentPersonal> filteredStudents = studentPersonalConsumer.Retrieve(studentPersonal);
6770

68-
foreach (StudentPersonal student in students)
71+
foreach (StudentPersonal student in filteredStudents)
6972
{
70-
if (log.IsInfoEnabled) log.Info("Student name is " + student.PersonInfo.Name.GivenName + " " + student.PersonInfo.Name.FamilyName);
73+
if (log.IsInfoEnabled) log.Info("Filtered student name is " + student.PersonInfo.Name.GivenName + " " + student.PersonInfo.Name.FamilyName);
7174
}
7275

73-
// Retrieve a single student.
74-
Guid studentId = students.ElementAt(0).Id;
75-
StudentPersonal firstStudent = studentPersonalConsumer.Retrieve(studentId);
76-
if (log.IsInfoEnabled) log.Info("Name of first student is " + firstStudent.PersonInfo.Name.GivenName + " " + firstStudent.PersonInfo.Name.FamilyName);
77-
7876
// Create and then retrieve a new student.
7977
Name newStudentName = new Name() { FamilyName = "Wayne", GivenName = "Bruce", Type = NameType.LGL };
8078
PersonInfo newStudentInfo = new PersonInfo() { Name = newStudentName };
@@ -84,12 +82,25 @@ void RunStudentPersonalConsumer()
8482
StudentPersonal retrievedNewStudent = studentPersonalConsumer.Retrieve(newStudentId);
8583
if (log.IsInfoEnabled) log.Info("Retrieved new student " + retrievedNewStudent.PersonInfo.Name.GivenName + " " + retrievedNewStudent.PersonInfo.Name.FamilyName);
8684

85+
// Retrieve all students.
86+
ICollection<StudentPersonal> students = studentPersonalConsumer.Retrieve();
87+
88+
foreach (StudentPersonal student in students)
89+
{
90+
if (log.IsInfoEnabled) log.Info("Student name is " + student.PersonInfo.Name.GivenName + " " + student.PersonInfo.Name.FamilyName);
91+
}
92+
93+
// Retrieve a single student.
94+
Guid studentId = students.ElementAt(1).Id;
95+
StudentPersonal secondStudent = studentPersonalConsumer.Retrieve(studentId);
96+
if (log.IsInfoEnabled) log.Info("Name of second student is " + secondStudent.PersonInfo.Name.GivenName + " " + secondStudent.PersonInfo.Name.FamilyName);
97+
8798
// Update that student and confirm.
88-
firstStudent.PersonInfo.Name.GivenName = "Homer";
89-
firstStudent.PersonInfo.Name.FamilyName = "Simpson";
90-
studentPersonalConsumer.Update(firstStudent);
91-
firstStudent = studentPersonalConsumer.Retrieve(studentId);
92-
if (log.IsInfoEnabled) log.Info("Name of first student has been changed to " + firstStudent.PersonInfo.Name.GivenName + " " + firstStudent.PersonInfo.Name.FamilyName);
99+
secondStudent.PersonInfo.Name.GivenName = "Homer";
100+
secondStudent.PersonInfo.Name.FamilyName = "Simpson";
101+
studentPersonalConsumer.Update(secondStudent);
102+
secondStudent = studentPersonalConsumer.Retrieve(studentId);
103+
if (log.IsInfoEnabled) log.Info("Name of second student has been changed to " + secondStudent.PersonInfo.Name.GivenName + " " + secondStudent.PersonInfo.Name.FamilyName);
93104

94105
// Delete that student and confirm.
95106
studentPersonalConsumer.Delete(studentId);
@@ -109,11 +120,11 @@ void RunStudentPersonalConsumer()
109120

110121
if (studentDeleted)
111122
{
112-
if (log.IsInfoEnabled) log.Info("Student " + firstStudent.PersonInfo.Name.GivenName + " " + firstStudent.PersonInfo.Name.FamilyName + " was successfully deleted.");
123+
if (log.IsInfoEnabled) log.Info("Student " + secondStudent.PersonInfo.Name.GivenName + " " + secondStudent.PersonInfo.Name.FamilyName + " was successfully deleted.");
113124
}
114125
else
115126
{
116-
if (log.IsInfoEnabled) log.Info("Student " + firstStudent.PersonInfo.Name.GivenName + " " + firstStudent.PersonInfo.Name.FamilyName + " was NOT deleted.");
127+
if (log.IsInfoEnabled) log.Info("Student " + secondStudent.PersonInfo.Name.GivenName + " " + secondStudent.PersonInfo.Name.FamilyName + " was NOT deleted.");
117128
}
118129

119130
}

0 commit comments

Comments
 (0)