I've used the hint in this thread and provided a default value, so that when a user doesnät specify the virutal sub-directory, I'm making the assumption that he meant all the stuff to be listed. It works.
[OperationContract]
[WebInvoke(UriTemplate = "GetStuff/{type=all}", ...]
IEnumerable<Stuff> GetStuff(String type);
However, it would be nicer to specify a default value, instead. However, default(String) is null and I'd like to sent in an actual value. Particularly, I've set my heart on String.Empty. However, I noticed that the following doesn't work. The condition on server side doesn't recognize the empty string (...where 'type' in (ColName, '', 'all')).
[OperationContract]
[WebInvoke(UriTemplate = "GetStuff/{type=String.Empty}", ...]
IEnumerable<Stuff> GetStuff(String type);
What to do?
You can't really have an empty default value in an UriTemplate, but you can have something which will mean a default value, and at the operation you can replace that with the actual default value you want, as shown below.
public class StackOverflow_17251719
{
const string DefaultValueMarker = "___DEFAULT_VALUE___";
const string ActualDefaultValue = "";
[ServiceContract]
public class Service
{
[WebInvoke(UriTemplate = "GetStuff/{type=" + DefaultValueMarker + "}", ResponseFormat = WebMessageFormat.Json)]
public IEnumerable<string> GetStuff(String type)
{
if (type == DefaultValueMarker)
{
type = ActualDefaultValue;
}
yield return type;
}
}
public static void SendBodylessPostRequest(string uri)
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
req.Method = "POST";
req.ContentType = "application/json";
req.GetRequestStream().Close(); // no request body
HttpWebResponse resp;
try
{
resp = (HttpWebResponse)req.GetResponse();
}
catch (WebException e)
{
resp = (HttpWebResponse)e.Response;
}
Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
foreach (string headerName in resp.Headers.AllKeys)
{
Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
}
Console.WriteLine();
Stream respStream = resp.GetResponseStream();
Console.WriteLine(new StreamReader(respStream).ReadToEnd());
Console.WriteLine();
Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* ");
Console.WriteLine();
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
SendBodylessPostRequest(baseAddress + "/GetStuff/nonDefault");
SendBodylessPostRequest(baseAddress + "/GetStuff");
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
It worked with "=null" for me. My contract looks like this:
[WebInvoke(UriTemplate = "UploadFile/{fileName}/{patientId}/{documentId}/{providerName=null}", Method = "POST")]
void UploadFile(string fileName, string patientId, string documentId, string providerName, Stream fileContents);
You do have the ability to add an optional parameter to your URITemplate. However, it has to be the last parameter.
Optional UriTemplate parameter using WebGet
when adding only '=' to get a default value which is empty for string variable it throws the message
The UriTemplate '/applications/legal/statuses/{serviceId=}' is not
valid; the UriTemplate variable declaration 'serviceId=' provides an
empty default value to path variable 'serviceId'. Note that
UriTemplate path variables cannot be bound to a null or empty value.
See the documentation for UriTemplate for more details.
instead assign a default value and check later in the code:
UriTemplate = "/applications/legal/statuses/{serviceId=default}"
service id will be default value.