commit
7f7a7547bb
93 changed files with 17628 additions and 4177 deletions
@ -0,0 +1,92 @@ |
||||
=============================================================================== |
||||
Welcome to the C# port of Google Protocol Buffers, written by Jon Skeet |
||||
(skeet@pobox.com) based on the work of many talented people. |
||||
|
||||
For more information about this port, visit its homepage: |
||||
http://protobuf-csharp-port.googlecode.com |
||||
|
||||
For more information about Protocol Buffers in general, visit the project page |
||||
for the C++, Java and Python project: |
||||
http://protobuf.googlecode.com |
||||
=============================================================================== |
||||
RELEASE NOTES - Version TBD |
||||
=============================================================================== |
||||
|
||||
(PENDING MERGE) |
||||
- Issue 20: Support for decorating classes [Serializable] |
||||
- Issue 22: Reusable Builder classes |
||||
- Issue 24: Support for using Json/Xml formats with ICodedInputStream |
||||
|
||||
Features: |
||||
- Added option service_generator_type to control service generation with |
||||
NONE, GENERIC, INTERFACE, or IRPCDISPATCH |
||||
- Added interfaces IRpcDispatch and IRpcServerStub to provide for blocking |
||||
services and implementations. |
||||
- Added ProtoGen.exe command-line argument "--protoc_dir=" to specify the |
||||
location of protoc.exe. |
||||
- Extracted interfaces for ICodedInputStream and ICodedOutputStream to allow |
||||
custom implementation of writers with both speed and size optimizations. |
||||
- Addition of the "Google.ProtoBuffers.Serialization" assembly to support |
||||
reading and writing messages to/from XML, JSON, IDictionary<,> and others. |
||||
- Several performance related fixes and tweeks |
||||
- Issue 3: Add option to mark generated code with attribute |
||||
- Issue 21: Decorate fields with [deprecated=true] as [System.Obsolete] |
||||
|
||||
Fixes: |
||||
- Issue 13: Message with Field same name as message causes uncompilable .cs |
||||
- Issue 16: Does not integrate well with other tooling |
||||
- Issue 19: Support for negative enum values |
||||
- Issue 26: AddRange in GeneratedBuilder iterates twice. |
||||
- Issue 27: Remove XML documentation output from test projects to clear |
||||
warnings/errors. |
||||
- Big-endian support for float, and double on Silverlight |
||||
- Packed and Unpacked parsing allow for all repeated, as per version 2.3 |
||||
- Fix for leaving Builder a public ctor on internal classes for use with |
||||
generic "where T: new()" constraints. |
||||
|
||||
Other: |
||||
- Reformatted all code and line-endings to C# defaults |
||||
- Reworking of performance benchmarks to produce reliable results, option /v2 |
||||
|
||||
=============================================================================== |
||||
RELEASE NOTES - Version 2.3.0.277 |
||||
=============================================================================== |
||||
|
||||
Features: |
||||
- Added cls_compliance option to generate attributes indicating |
||||
non-CLS-compliance. |
||||
- Added file_extension option to control the generated output file's extension. |
||||
- Added umbrella_namespace option to place the umbrella class into a nested |
||||
namespace to address issues with proto files having the same name as a |
||||
message it contains. |
||||
- Added output_directory option to set the output path for the source file(s). |
||||
- Added ignore_google_protobuf option to avoid generating code for includes |
||||
from the google.protobuf package. |
||||
- Added the LITE framework (Google.ProtoBuffersLite.dll) and the ability to |
||||
generate code with "option optimize_for = LITE_RUNTIME;". |
||||
- Added ability to invoke protoc.exe from within ProtoGen.exe. |
||||
- Upgraded to protoc.exe (2.3) compiler. |
||||
|
||||
Fixes: |
||||
- Issue 9: Class cannot be static and sealed error |
||||
- Issue 12: default value for enumerate fields must be filled out |
||||
|
||||
Other: |
||||
- Rewrite of build using MSBbuild instead of NAnt |
||||
- Moved to NUnit Version 2.2.8.0 |
||||
- Changed to using secure .snk for releases |
||||
|
||||
=============================================================================== |
||||
RELEASE NOTES - Version 0.9.1 |
||||
=============================================================================== |
||||
|
||||
Fixes: |
||||
- issue 10: Incorrect encoding of packed fields when serialized |
||||
|
||||
=============================================================================== |
||||
RELEASE NOTES - Version 0.9.0 |
||||
=============================================================================== |
||||
|
||||
- Initial release |
||||
|
||||
=============================================================================== |
@ -0,0 +1,44 @@ |
||||
<NotepadPlus> |
||||
<!-- |
||||
Defines syntax highlighting for Notepad++. |
||||
1. Install Notepad++ from http://notepad-plus-plus.org |
||||
2. Open Notepad++, from the View menu, select "User-Defined Dialog..." |
||||
3. Click the "Import..." button and select this file |
||||
4. Restart Notepad++ |
||||
5. Open and edit any *.proto file |
||||
--> |
||||
<UserLang name="Proto Buffer" ext="proto"> |
||||
<Settings> |
||||
<Global caseIgnored="no" /> |
||||
<TreatAsSymbol comment="no" commentLine="yes" /> |
||||
<Prefix words1="no" words2="no" words3="no" words4="yes" /> |
||||
</Settings> |
||||
<KeywordLists> |
||||
<Keywords name="Delimiters">[00]00</Keywords> |
||||
<Keywords name="Folder+">{</Keywords> |
||||
<Keywords name="Folder-">}</Keywords> |
||||
<Keywords name="Operators">=</Keywords> |
||||
<Keywords name="Comment"> 1option 1package 1import 2; 0//</Keywords> |
||||
<Keywords name="Words1">message enum service extend</Keywords> |
||||
<Keywords name="Words2">required optional repeated extensions to rpc returns</Keywords> |
||||
<Keywords name="Words3">double float int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64 bool string bytes</Keywords> |
||||
<Keywords name="Words4"></Keywords> |
||||
</KeywordLists> |
||||
<Styles> |
||||
<WordsStyle name="DEFAULT" styleID="11" fgColor="000000" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="FOLDEROPEN" styleID="12" fgColor="000000" bgColor="FFFFFF" fontStyle="1" /> |
||||
<WordsStyle name="FOLDERCLOSE" styleID="13" fgColor="000000" bgColor="FFFFFF" fontStyle="1" /> |
||||
<WordsStyle name="KEYWORD1" styleID="5" fgColor="0000FF" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="KEYWORD2" styleID="6" fgColor="0080C0" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="KEYWORD3" styleID="7" fgColor="0000FF" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="KEYWORD4" styleID="8" fgColor="008040" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="COMMENT" styleID="1" fgColor="008000" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="COMMENT LINE" styleID="2" fgColor="949494" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="NUMBER" styleID="4" fgColor="FF0000" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="OPERATOR" styleID="10" fgColor="000000" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="DELIMINER1" styleID="14" fgColor="800080" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="DELIMINER2" styleID="15" fgColor="808080" bgColor="FFFFFF" fontStyle="0" /> |
||||
<WordsStyle name="DELIMINER3" styleID="16" fgColor="000000" bgColor="FFFFFF" fontStyle="0" /> |
||||
</Styles> |
||||
</UserLang> |
||||
</NotepadPlus> |
@ -1,40 +0,0 @@ |
||||
Welcome to the C# port of Google Protocol Buffers, written by Jon Skeet |
||||
(skeet@pobox.com) based on the work of many talented people. |
||||
|
||||
For more information about this port, visit its homepage: |
||||
http://protobuf-csharp-port.googlecode.com |
||||
|
||||
For more information about Protocol Buffers in general, visit the |
||||
project page for the C++, Java and Python project: |
||||
http://protobuf.googlecode.com |
||||
|
||||
|
||||
Release 0.9.1 |
||||
------------- |
||||
|
||||
Fix to release 0.9: |
||||
|
||||
- Include protos in binary download |
||||
- Fix issue 10: incorrect encoding of packed fields when serialized |
||||
size wasn't fetched first |
||||
|
||||
|
||||
Release 0.9 |
||||
----------- |
||||
|
||||
Due to popular demand, I have built a version of the binaries to put |
||||
on the web site. Currently these are set at assembly version 0.9, |
||||
and an assembly file version of 0.9. This should be seen as a mark |
||||
of the readiness of the release process more than the stability of |
||||
the code. As far as I'm aware, the code itself is perfectly fine: I |
||||
certainly have plans for more features particularly around making |
||||
code generation simpler, but you should feel confident about the |
||||
parsing and serialization of messages produced with this version of |
||||
the library. Of course, if you do find any problems, *please* report |
||||
them at the web site. |
||||
|
||||
Currently the downloadable release is built with the snk file which |
||||
is in the open source library. I am considering having a privately |
||||
held key so that you can check that you're building against a |
||||
"blessed" release - feedback on this (and any other aspect of the |
||||
release process) is very welcome. |
@ -0,0 +1,162 @@ |
||||
using System; |
||||
using System.IO; |
||||
using System.Text; |
||||
|
||||
namespace Google.ProtocolBuffers.Serialization.Http |
||||
{ |
||||
/// <summary> |
||||
/// Allows reading messages from a name/value dictionary |
||||
/// </summary> |
||||
public class FormUrlEncodedReader : AbstractTextReader |
||||
{ |
||||
private readonly TextReader _input; |
||||
private string _fieldName, _fieldValue; |
||||
private bool _ready; |
||||
|
||||
/// <summary> |
||||
/// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary |
||||
/// </summary> |
||||
FormUrlEncodedReader(TextReader input) |
||||
{ |
||||
_input = input; |
||||
int ch = input.Peek(); |
||||
if (ch == '?') |
||||
{ |
||||
input.Read(); |
||||
} |
||||
_ready = ReadNext(); |
||||
} |
||||
|
||||
#region CreateInstance overloads |
||||
/// <summary> |
||||
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message. |
||||
/// </summary> |
||||
public static FormUrlEncodedReader CreateInstance(Stream stream) |
||||
{ |
||||
return new FormUrlEncodedReader(new StreamReader(stream, Encoding.UTF8, false)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message. |
||||
/// </summary> |
||||
public static FormUrlEncodedReader CreateInstance(byte[] bytes) |
||||
{ |
||||
return new FormUrlEncodedReader(new StreamReader(new MemoryStream(bytes, false), Encoding.UTF8, false)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message. |
||||
/// </summary> |
||||
public static FormUrlEncodedReader CreateInstance(string text) |
||||
{ |
||||
return new FormUrlEncodedReader(new StringReader(text)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Constructs a FormUrlEncodedReader to parse form data, or url query text into a message. |
||||
/// </summary> |
||||
public static FormUrlEncodedReader CreateInstance(TextReader input) |
||||
{ |
||||
return new FormUrlEncodedReader(input); |
||||
} |
||||
#endregion |
||||
|
||||
private bool ReadNext() |
||||
{ |
||||
StringBuilder field = new StringBuilder(32); |
||||
StringBuilder value = new StringBuilder(64); |
||||
int ch; |
||||
while (-1 != (ch = _input.Read()) && ch != '=' && ch != '&') |
||||
{ |
||||
field.Append((char)ch); |
||||
} |
||||
|
||||
if (ch != -1 && ch != '&') |
||||
{ |
||||
while (-1 != (ch = _input.Read()) && ch != '&') |
||||
{ |
||||
value.Append((char)ch); |
||||
} |
||||
} |
||||
|
||||
_fieldName = field.ToString(); |
||||
_fieldValue = Uri.UnescapeDataString(value.Replace('+', ' ').ToString()); |
||||
|
||||
return !String.IsNullOrEmpty(_fieldName); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// No-op |
||||
/// </summary> |
||||
public override void ReadMessageStart() |
||||
{ } |
||||
|
||||
/// <summary> |
||||
/// No-op |
||||
/// </summary> |
||||
public override void ReadMessageEnd() |
||||
{ } |
||||
|
||||
/// <summary> |
||||
/// Merges the contents of stream into the provided message builder |
||||
/// </summary> |
||||
public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry) |
||||
{ |
||||
builder.WeakMergeFrom(this, registry); |
||||
return builder; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Causes the reader to skip past this field |
||||
/// </summary> |
||||
protected override void Skip() |
||||
{ |
||||
_ready = ReadNext(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Peeks at the next field in the input stream and returns what information is available. |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// This may be called multiple times without actually reading the field. Only after the field |
||||
/// is either read, or skipped, should PeekNext return a different value. |
||||
/// </remarks> |
||||
protected override bool PeekNext(out string field) |
||||
{ |
||||
field = _ready ? _fieldName : null; |
||||
return field != null; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns true if it was able to read a String from the input |
||||
/// </summary> |
||||
protected override bool ReadAsText(ref string value, Type typeInfo) |
||||
{ |
||||
if (_ready) |
||||
{ |
||||
value = _fieldValue; |
||||
_ready = ReadNext(); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// It's unlikely this will work for anything but text data as bytes UTF8 are transformed to text and back to bytes |
||||
/// </summary> |
||||
protected override ByteString DecodeBytes(string bytes) |
||||
{ return ByteString.CopyFromUtf8(bytes); } |
||||
|
||||
/// <summary> |
||||
/// Not Supported |
||||
/// </summary> |
||||
public override bool ReadGroup(IBuilderLite value, ExtensionRegistry registry) |
||||
{ throw new NotSupportedException(); } |
||||
|
||||
/// <summary> |
||||
/// Not Supported |
||||
/// </summary> |
||||
protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry) |
||||
{ throw new NotSupportedException(); } |
||||
} |
||||
} |
@ -0,0 +1,153 @@ |
||||
using System; |
||||
using System.IO; |
||||
using System.Xml; |
||||
using System.Text; |
||||
|
||||
namespace Google.ProtocolBuffers.Serialization.Http |
||||
{ |
||||
/// <summary> |
||||
/// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type. |
||||
/// </summary> |
||||
public static class MessageFormatFactory |
||||
{ |
||||
/// <summary> |
||||
/// Constructs an ICodedInputStream from the input stream based on the contentType provided |
||||
/// </summary> |
||||
/// <param name="options">Options specific to reading this message and/or content type</param> |
||||
/// <param name="contentType">The mime type of the input stream content</param> |
||||
/// <param name="input">The stream to read the message from</param> |
||||
/// <returns>The ICodedInputStream that can be given to the IBuilder.MergeFrom(...) method</returns> |
||||
public static ICodedInputStream CreateInputStream(MessageFormatOptions options, string contentType, Stream input) |
||||
{ |
||||
ICodedInputStream codedInput = ContentTypeToInputStream(contentType, options, input); |
||||
|
||||
if (codedInput is XmlFormatReader) |
||||
{ |
||||
XmlFormatReader reader = (XmlFormatReader)codedInput; |
||||
reader.RootElementName = options.XmlReaderRootElementName; |
||||
reader.Options = options.XmlReaderOptions; |
||||
} |
||||
|
||||
return codedInput; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Merges the message from the input stream based on the contentType provided |
||||
/// </summary> |
||||
/// <typeparam name="TBuilder">A type derived from IBuilderLite</typeparam> |
||||
/// <param name="builder">An instance of a message builder</param> |
||||
/// <param name="options">Options specific to reading this message and/or content type</param> |
||||
/// <param name="contentType">The mime type of the input stream content</param> |
||||
/// <param name="input">The stream to read the message from</param> |
||||
/// <returns>The same builder instance that was supplied in the builder parameter</returns> |
||||
public static TBuilder MergeFrom<TBuilder>(this TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite |
||||
{ |
||||
ICodedInputStream codedInput = CreateInputStream(options, contentType, input); |
||||
codedInput.ReadMessageStart(); |
||||
builder.WeakMergeFrom(codedInput, options.ExtensionRegistry); |
||||
codedInput.ReadMessageEnd(); |
||||
return builder; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Writes the message instance to the stream using the content type provided |
||||
/// </summary> |
||||
/// <param name="options">Options specific to writing this message and/or content type</param> |
||||
/// <param name="contentType">The mime type of the content to be written</param> |
||||
/// <param name="output">The stream to write the message to</param> |
||||
/// <remarks> If you do not dispose of ICodedOutputStream some formats may yield incomplete output </remarks> |
||||
public static ICodedOutputStream CreateOutputStream(MessageFormatOptions options, string contentType, Stream output) |
||||
{ |
||||
ICodedOutputStream codedOutput = ContentTypeToOutputStream(contentType, options, output); |
||||
|
||||
if (codedOutput is JsonFormatWriter) |
||||
{ |
||||
JsonFormatWriter writer = (JsonFormatWriter)codedOutput; |
||||
if (options.FormattedOutput) |
||||
{ |
||||
writer.Formatted(); |
||||
} |
||||
} |
||||
else if (codedOutput is XmlFormatWriter) |
||||
{ |
||||
XmlFormatWriter writer = (XmlFormatWriter)codedOutput; |
||||
if (options.FormattedOutput) |
||||
{ |
||||
XmlWriterSettings settings = new XmlWriterSettings() |
||||
{ |
||||
CheckCharacters = false, |
||||
NewLineHandling = NewLineHandling.Entitize, |
||||
OmitXmlDeclaration = true, |
||||
Encoding = new UTF8Encoding(false), |
||||
Indent = true, |
||||
IndentChars = " ", |
||||
NewLineChars = Environment.NewLine, |
||||
}; |
||||
// Don't know how else to change xml writer options? |
||||
codedOutput = writer = XmlFormatWriter.CreateInstance(XmlWriter.Create(output, settings)); |
||||
} |
||||
writer.RootElementName = options.XmlWriterRootElementName; |
||||
writer.Options = options.XmlWriterOptions; |
||||
} |
||||
|
||||
return codedOutput; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Writes the message instance to the stream using the content type provided |
||||
/// </summary> |
||||
/// <param name="message">An instance of a message</param> |
||||
/// <param name="options">Options specific to writing this message and/or content type</param> |
||||
/// <param name="contentType">The mime type of the content to be written</param> |
||||
/// <param name="output">The stream to write the message to</param> |
||||
public static void WriteTo(this IMessageLite message, MessageFormatOptions options, string contentType, Stream output) |
||||
{ |
||||
ICodedOutputStream codedOutput = CreateOutputStream(options, contentType, output); |
||||
|
||||
// Output the appropriate message preamble |
||||
codedOutput.WriteMessageStart(); |
||||
|
||||
// Write the message content to the output |
||||
message.WriteTo(codedOutput); |
||||
|
||||
// Write the closing message fragment |
||||
codedOutput.WriteMessageEnd(); |
||||
codedOutput.Flush(); |
||||
} |
||||
|
||||
private static ICodedInputStream ContentTypeToInputStream(string contentType, MessageFormatOptions options, Stream input) |
||||
{ |
||||
contentType = (contentType ?? String.Empty).Split(';')[0].Trim(); |
||||
|
||||
Converter<Stream, ICodedInputStream> factory; |
||||
if(!options.MimeInputTypesReadOnly.TryGetValue(contentType, out factory) || factory == null) |
||||
{ |
||||
if(String.IsNullOrEmpty(options.DefaultContentType) || |
||||
!options.MimeInputTypesReadOnly.TryGetValue(options.DefaultContentType, out factory) || factory == null) |
||||
{ |
||||
throw new ArgumentOutOfRangeException("contentType"); |
||||
} |
||||
} |
||||
|
||||
return factory(input); |
||||
} |
||||
|
||||
private static ICodedOutputStream ContentTypeToOutputStream(string contentType, MessageFormatOptions options, Stream output) |
||||
{ |
||||
contentType = (contentType ?? String.Empty).Split(';')[0].Trim(); |
||||
|
||||
Converter<Stream, ICodedOutputStream> factory; |
||||
if (!options.MimeOutputTypesReadOnly.TryGetValue(contentType, out factory) || factory == null) |
||||
{ |
||||
if (String.IsNullOrEmpty(options.DefaultContentType) || |
||||
!options.MimeOutputTypesReadOnly.TryGetValue(options.DefaultContentType, out factory) || factory == null) |
||||
{ |
||||
throw new ArgumentOutOfRangeException("contentType"); |
||||
} |
||||
} |
||||
|
||||
return factory(output); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,167 @@ |
||||
using System; |
||||
using System.IO; |
||||
using System.Collections.Generic; |
||||
using Google.ProtocolBuffers.Collections; |
||||
|
||||
namespace Google.ProtocolBuffers.Serialization.Http |
||||
{ |
||||
/// <summary> |
||||
/// Defines control information for the various formatting used with HTTP services |
||||
/// </summary> |
||||
public class MessageFormatOptions |
||||
{ |
||||
/// <summary>The mime type for xml content</summary> |
||||
/// <remarks>Other valid xml mime types include: application/binary, application/x-protobuf</remarks> |
||||
public const string ContentTypeProtoBuffer = "application/vnd.google.protobuf"; |
||||
|
||||
/// <summary>The mime type for xml content</summary> |
||||
/// <remarks>Other valid xml mime types include: text/xml</remarks> |
||||
public const string ContentTypeXml = "application/xml"; |
||||
|
||||
/// <summary>The mime type for json content</summary> |
||||
/// <remarks> |
||||
/// Other valid json mime types include: application/json, application/x-json, |
||||
/// application/x-javascript, text/javascript, text/x-javascript, text/x-json, text/json |
||||
/// </remarks> |
||||
public const string ContentTypeJson = "application/json"; |
||||
|
||||
/// <summary>The mime type for query strings and x-www-form-urlencoded content</summary> |
||||
/// <remarks>This mime type is input-only</remarks> |
||||
public const string ContentFormUrlEncoded = "application/x-www-form-urlencoded"; |
||||
|
||||
/// <summary> |
||||
/// Default mime-type handling for input |
||||
/// </summary> |
||||
private static readonly IDictionary<string, Converter<Stream, ICodedInputStream>> MimeInputDefaults = |
||||
new ReadOnlyDictionary<string, Converter<Stream, ICodedInputStream>>( |
||||
new Dictionary<string, Converter<Stream, ICodedInputStream>>(StringComparer.OrdinalIgnoreCase) |
||||
{ |
||||
{"application/json", JsonFormatReader.CreateInstance}, |
||||
{"application/x-json", JsonFormatReader.CreateInstance}, |
||||
{"application/x-javascript", JsonFormatReader.CreateInstance}, |
||||
{"text/javascript", JsonFormatReader.CreateInstance}, |
||||
{"text/x-javascript", JsonFormatReader.CreateInstance}, |
||||
{"text/x-json", JsonFormatReader.CreateInstance}, |
||||
{"text/json", JsonFormatReader.CreateInstance}, |
||||
{"text/xml", XmlFormatReader.CreateInstance}, |
||||
{"application/xml", XmlFormatReader.CreateInstance}, |
||||
{"application/binary", CodedInputStream.CreateInstance}, |
||||
{"application/x-protobuf", CodedInputStream.CreateInstance}, |
||||
{"application/vnd.google.protobuf", CodedInputStream.CreateInstance}, |
||||
{"application/x-www-form-urlencoded", FormUrlEncodedReader.CreateInstance}, |
||||
} |
||||
); |
||||
|
||||
/// <summary> |
||||
/// Default mime-type handling for output |
||||
/// </summary> |
||||
private static readonly IDictionary<string, Converter<Stream, ICodedOutputStream>> MimeOutputDefaults = |
||||
new ReadOnlyDictionary<string, Converter<Stream, ICodedOutputStream>>( |
||||
new Dictionary<string, Converter<Stream, ICodedOutputStream>>(StringComparer.OrdinalIgnoreCase) |
||||
{ |
||||
{"application/json", JsonFormatWriter.CreateInstance}, |
||||
{"application/x-json", JsonFormatWriter.CreateInstance}, |
||||
{"application/x-javascript", JsonFormatWriter.CreateInstance}, |
||||
{"text/javascript", JsonFormatWriter.CreateInstance}, |
||||
{"text/x-javascript", JsonFormatWriter.CreateInstance}, |
||||
{"text/x-json", JsonFormatWriter.CreateInstance}, |
||||
{"text/json", JsonFormatWriter.CreateInstance}, |
||||
{"text/xml", XmlFormatWriter.CreateInstance}, |
||||
{"application/xml", XmlFormatWriter.CreateInstance}, |
||||
{"application/binary", CodedOutputStream.CreateInstance}, |
||||
{"application/x-protobuf", CodedOutputStream.CreateInstance}, |
||||
{"application/vnd.google.protobuf", CodedOutputStream.CreateInstance}, |
||||
} |
||||
); |
||||
|
||||
|
||||
|
||||
|
||||
private string _defaultContentType; |
||||
private string _xmlReaderRootElementName; |
||||
private string _xmlWriterRootElementName; |
||||
private ExtensionRegistry _extensionRegistry; |
||||
private Dictionary<string, Converter<Stream, ICodedInputStream>> _mimeInputTypes; |
||||
private Dictionary<string, Converter<Stream, ICodedOutputStream>> _mimeOutputTypes; |
||||
|
||||
/// <summary> Provides access to modify the mime-type input stream construction </summary> |
||||
public IDictionary<string, Converter<Stream, ICodedInputStream>> MimeInputTypes |
||||
{ |
||||
get |
||||
{ |
||||
return _mimeInputTypes ?? |
||||
(_mimeInputTypes = new Dictionary<string, Converter<Stream, ICodedInputStream>>( |
||||
MimeInputDefaults, StringComparer.OrdinalIgnoreCase)); |
||||
} |
||||
} |
||||
|
||||
/// <summary> Provides access to modify the mime-type input stream construction </summary> |
||||
public IDictionary<string, Converter<Stream, ICodedOutputStream>> MimeOutputTypes |
||||
{ |
||||
get |
||||
{ |
||||
return _mimeOutputTypes ?? |
||||
(_mimeOutputTypes = new Dictionary<string, Converter<Stream, ICodedOutputStream>>( |
||||
MimeOutputDefaults, StringComparer.OrdinalIgnoreCase)); |
||||
} |
||||
} |
||||
|
||||
internal IDictionary<string, Converter<Stream, ICodedInputStream>> MimeInputTypesReadOnly |
||||
{ get { return _mimeInputTypes ?? MimeInputDefaults; } } |
||||
|
||||
internal IDictionary<string, Converter<Stream, ICodedOutputStream>> MimeOutputTypesReadOnly |
||||
{ get { return _mimeOutputTypes ?? MimeOutputDefaults; } } |
||||
|
||||
/// <summary> |
||||
/// The default content type to use if the input type is null or empty. If this |
||||
/// value is not supplied an ArgumentOutOfRangeException exception will be raised. |
||||
/// </summary> |
||||
public string DefaultContentType |
||||
{ |
||||
get { return _defaultContentType ?? String.Empty; } |
||||
set { _defaultContentType = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// The extension registry to use when reading messages |
||||
/// </summary> |
||||
public ExtensionRegistry ExtensionRegistry |
||||
{ |
||||
get { return _extensionRegistry ?? ExtensionRegistry.Empty; } |
||||
set { _extensionRegistry = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// The name of the xml root element when reading messages |
||||
/// </summary> |
||||
public string XmlReaderRootElementName |
||||
{ |
||||
get { return _xmlReaderRootElementName ?? XmlFormatReader.DefaultRootElementName; } |
||||
set { _xmlReaderRootElementName = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Xml reader options |
||||
/// </summary> |
||||
public XmlReaderOptions XmlReaderOptions { get; set; } |
||||
|
||||
/// <summary> |
||||
/// True to use formatted output including new-lines and default indentation |
||||
/// </summary> |
||||
public bool FormattedOutput { get; set; } |
||||
|
||||
/// <summary> |
||||
/// The name of the xml root element when writing messages |
||||
/// </summary> |
||||
public string XmlWriterRootElementName |
||||
{ |
||||
get { return _xmlWriterRootElementName ?? XmlFormatWriter.DefaultRootElementName; } |
||||
set { _xmlWriterRootElementName = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Xml writer options |
||||
/// </summary> |
||||
public XmlWriterOptions XmlWriterOptions { get; set; } |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@ |
||||
using System; |
||||
using System.IO; |
||||
using System.Text; |
||||
using NUnit.Framework; |
||||
using Google.ProtocolBuffers.TestProtos; |
||||
using Google.ProtocolBuffers.Serialization.Http; |
||||
|
||||
namespace Google.ProtocolBuffers |
||||
{ |
||||
[TestFixture] |
||||
public class TestReaderForUrlEncoded |
||||
{ |
||||
[Test] |
||||
public void Example_FromQueryString() |
||||
{ |
||||
Uri sampleUri = new Uri("http://sample.com/Path/File.ext?text=two+three%20four&valid=true&numbers=1&numbers=2", UriKind.Absolute); |
||||
|
||||
ICodedInputStream input = FormUrlEncodedReader.CreateInstance(sampleUri.Query); |
||||
|
||||
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); |
||||
builder.MergeFrom(input); |
||||
|
||||
TestXmlMessage message = builder.Build(); |
||||
Assert.AreEqual(true, message.Valid); |
||||
Assert.AreEqual("two three four", message.Text); |
||||
Assert.AreEqual(2, message.NumbersCount); |
||||
Assert.AreEqual(1, message.NumbersList[0]); |
||||
Assert.AreEqual(2, message.NumbersList[1]); |
||||
} |
||||
|
||||
[Test] |
||||
public void Example_FromFormData() |
||||
{ |
||||
Stream rawPost = new MemoryStream(Encoding.UTF8.GetBytes("text=two+three%20four&valid=true&numbers=1&numbers=2"), false); |
||||
|
||||
ICodedInputStream input = FormUrlEncodedReader.CreateInstance(rawPost); |
||||
|
||||
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); |
||||
builder.MergeFrom(input); |
||||
|
||||
TestXmlMessage message = builder.Build(); |
||||
Assert.AreEqual(true, message.Valid); |
||||
Assert.AreEqual("two three four", message.Text); |
||||
Assert.AreEqual(2, message.NumbersCount); |
||||
Assert.AreEqual(1, message.NumbersList[0]); |
||||
Assert.AreEqual(2, message.NumbersList[1]); |
||||
} |
||||
|
||||
[Test] |
||||
public void TestEmptyValues() |
||||
{ |
||||
ICodedInputStream input = FormUrlEncodedReader.CreateInstance("valid=true&text=&numbers=1"); |
||||
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); |
||||
builder.MergeFrom(input); |
||||
|
||||
Assert.IsTrue(builder.Valid); |
||||
Assert.IsTrue(builder.HasText); |
||||
Assert.AreEqual("", builder.Text); |
||||
Assert.AreEqual(1, builder.NumbersCount); |
||||
Assert.AreEqual(1, builder.NumbersList[0]); |
||||
} |
||||
|
||||
[Test] |
||||
public void TestNoValue() |
||||
{ |
||||
ICodedInputStream input = FormUrlEncodedReader.CreateInstance("valid=true&text&numbers=1"); |
||||
TestXmlMessage.Builder builder = TestXmlMessage.CreateBuilder(); |
||||
builder.MergeFrom(input); |
||||
|
||||
Assert.IsTrue(builder.Valid); |
||||
Assert.IsTrue(builder.HasText); |
||||
Assert.AreEqual("", builder.Text); |
||||
Assert.AreEqual(1, builder.NumbersCount); |
||||
Assert.AreEqual(1, builder.NumbersList[0]); |
||||
} |
||||
|
||||
[Test, ExpectedException(typeof(NotSupportedException))] |
||||
public void FormUrlEncodedReaderDoesNotSupportChildren() |
||||
{ |
||||
ICodedInputStream input = FormUrlEncodedReader.CreateInstance("child=uh0"); |
||||
TestXmlMessage.CreateBuilder().MergeFrom(input); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,386 @@ |
||||
#region Copyright notice and license |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// http://github.com/jskeet/dotnet-protobufs/ |
||||
// Original C++/Java/Python code: |
||||
// http://code.google.com/p/protobuf/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
#endregion |
||||
|
||||
using System; |
||||
using Google.ProtocolBuffers; |
||||
using Google.ProtocolBuffers.Serialization.Http; |
||||
using Google.ProtocolBuffers.TestProtos; |
||||
using NUnit.Framework; |
||||
using System.IO; |
||||
using Google.ProtocolBuffers.Serialization; |
||||
using System.Text; |
||||
|
||||
namespace Google.ProtocolBuffers |
||||
{ |
||||
/// <summary> |
||||
/// This class verifies the correct code is generated from unittest_rpc_interop.proto and provides a small demonstration |
||||
/// of using the new IRpcDispatch to write a client/server |
||||
/// </summary> |
||||
[TestFixture] |
||||
public class TestRpcForMimeTypes |
||||
{ |
||||
/// <summary> |
||||
/// A sample implementation of the ISearchService for testing |
||||
/// </summary> |
||||
private class ExampleSearchImpl : ISearchService |
||||
{ |
||||
SearchResponse ISearchService.Search(SearchRequest searchRequest) |
||||
{ |
||||
if (searchRequest.CriteriaCount == 0) |
||||
{ |
||||
throw new ArgumentException("No criteria specified.", new InvalidOperationException()); |
||||
} |
||||
SearchResponse.Builder resp = SearchResponse.CreateBuilder(); |
||||
foreach (string criteria in searchRequest.CriteriaList) |
||||
{ |
||||
resp.AddResults( |
||||
SearchResponse.Types.ResultItem.CreateBuilder().SetName(criteria).SetUrl("http://search.com"). |
||||
Build()); |
||||
} |
||||
return resp.Build(); |
||||
} |
||||
|
||||
SearchResponse ISearchService.RefineSearch(RefineSearchRequest refineSearchRequest) |
||||
{ |
||||
SearchResponse.Builder resp = refineSearchRequest.PreviousResults.ToBuilder(); |
||||
foreach (string criteria in refineSearchRequest.CriteriaList) |
||||
{ |
||||
resp.AddResults( |
||||
SearchResponse.Types.ResultItem.CreateBuilder().SetName(criteria).SetUrl("http://refine.com"). |
||||
Build()); |
||||
} |
||||
return resp.Build(); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// An example extraction of the wire protocol |
||||
/// </summary> |
||||
private interface IHttpTransfer |
||||
{ |
||||
void Execute(string method, string contentType, Stream input, string acceptType, Stream output); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// An example of a server responding to a web/http request |
||||
/// </summary> |
||||
private class ExampleHttpServer : IHttpTransfer |
||||
{ |
||||
public readonly MessageFormatOptions Options = |
||||
new MessageFormatOptions |
||||
{ |
||||
ExtensionRegistry = ExtensionRegistry.Empty, |
||||
FormattedOutput = true, |
||||
XmlReaderOptions = XmlReaderOptions.ReadNestedArrays, |
||||
XmlReaderRootElementName = "request", |
||||
XmlWriterOptions = XmlWriterOptions.OutputNestedArrays, |
||||
XmlWriterRootElementName = "response" |
||||
}; |
||||
|
||||
private readonly IRpcServerStub _stub; |
||||
|
||||
public ExampleHttpServer(ISearchService implementation) |
||||
{ |
||||
//on the server, we create a dispatch to call the appropriate method by name |
||||
IRpcDispatch dispatch = new SearchService.Dispatch(implementation); |
||||
//we then wrap that dispatch in a server stub which will deserialize the wire bytes to the message |
||||
//type appropriate for the method name being invoked. |
||||
_stub = new SearchService.ServerStub(dispatch); |
||||
} |
||||
|
||||
void IHttpTransfer.Execute(string method, string contentType, Stream input, string acceptType, Stream output) |
||||
{ |
||||
//Extension for: Google.ProtocolBuffers.Serialization.Http.ServiceExtensions.HttpCallMethod(_stub, |
||||
_stub.HttpCallMethod( |
||||
method, Options, |
||||
contentType, input, |
||||
acceptType, output |
||||
); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// An example of a client sending a wire request |
||||
/// </summary> |
||||
private class ExampleClient : IRpcDispatch |
||||
{ |
||||
public readonly MessageFormatOptions Options = |
||||
new MessageFormatOptions |
||||
{ |
||||
ExtensionRegistry = ExtensionRegistry.Empty, |
||||
FormattedOutput = true, |
||||
XmlReaderOptions = XmlReaderOptions.ReadNestedArrays, |
||||
XmlReaderRootElementName = "response", |
||||
XmlWriterOptions = XmlWriterOptions.OutputNestedArrays, |
||||
XmlWriterRootElementName = "request" |
||||
}; |
||||
|
||||
|
||||
private readonly IHttpTransfer _wire; |
||||
private readonly string _mimeType; |
||||
|
||||
public ExampleClient(IHttpTransfer wire, string mimeType) |
||||
{ |
||||
_wire = wire; |
||||
_mimeType = mimeType; |
||||
} |
||||
|
||||
TMessage IRpcDispatch.CallMethod<TMessage, TBuilder>(string method, IMessageLite request, |
||||
IBuilderLite<TMessage, TBuilder> response) |
||||
{ |
||||
MemoryStream input = new MemoryStream(); |
||||
MemoryStream output = new MemoryStream(); |
||||
|
||||
//Write to _mimeType format |
||||
request.WriteTo(Options, _mimeType, input); |
||||
|
||||
input.Position = 0; |
||||
_wire.Execute(method, _mimeType, input, _mimeType, output); |
||||
|
||||
//Read from _mimeType format |
||||
output.Position = 0; |
||||
response.MergeFrom(Options, _mimeType, output); |
||||
|
||||
return response.Build(); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test] |
||||
public void TestClientServerWithJsonFormat() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
ISearchService client = new SearchService(new ExampleClient(wire, "text/json")); |
||||
//now the client has a real, typed, interface to work with: |
||||
SearchResponse result = client.Search(SearchRequest.CreateBuilder().AddCriteria("Test").Build()); |
||||
Assert.AreEqual(1, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
//The test part of this, call the only other method |
||||
result = |
||||
client.RefineSearch( |
||||
RefineSearchRequest.CreateBuilder().SetPreviousResults(result).AddCriteria("Refine").Build()); |
||||
Assert.AreEqual(2, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
Assert.AreEqual("Refine", result.ResultsList[1].Name); |
||||
Assert.AreEqual("http://refine.com", result.ResultsList[1].Url); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test] |
||||
public void TestClientServerWithXmlFormat() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
ISearchService client = new SearchService(new ExampleClient(wire, "text/xml")); |
||||
//now the client has a real, typed, interface to work with: |
||||
SearchResponse result = client.Search(SearchRequest.CreateBuilder().AddCriteria("Test").Build()); |
||||
Assert.AreEqual(1, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
//The test part of this, call the only other method |
||||
result = |
||||
client.RefineSearch( |
||||
RefineSearchRequest.CreateBuilder().SetPreviousResults(result).AddCriteria("Refine").Build()); |
||||
Assert.AreEqual(2, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
Assert.AreEqual("Refine", result.ResultsList[1].Name); |
||||
Assert.AreEqual("http://refine.com", result.ResultsList[1].Url); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test] |
||||
public void TestClientServerWithProtoFormat() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
ISearchService client = new SearchService(new ExampleClient(wire, "application/x-protobuf")); |
||||
//now the client has a real, typed, interface to work with: |
||||
SearchResponse result = client.Search(SearchRequest.CreateBuilder().AddCriteria("Test").Build()); |
||||
Assert.AreEqual(1, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
//The test part of this, call the only other method |
||||
result = |
||||
client.RefineSearch( |
||||
RefineSearchRequest.CreateBuilder().SetPreviousResults(result).AddCriteria("Refine").Build()); |
||||
Assert.AreEqual(2, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
Assert.AreEqual("Refine", result.ResultsList[1].Name); |
||||
Assert.AreEqual("http://refine.com", result.ResultsList[1].Url); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test] |
||||
public void TestClientServerWithCustomFormat() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
//Setup our custom mime-type format as the only format supported: |
||||
server.Options.MimeInputTypes.Clear(); |
||||
server.Options.MimeInputTypes.Add("foo/bar", CodedInputStream.CreateInstance); |
||||
server.Options.MimeOutputTypes.Clear(); |
||||
server.Options.MimeOutputTypes.Add("foo/bar", CodedOutputStream.CreateInstance); |
||||
|
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
ExampleClient exclient = new ExampleClient(wire, "foo/bar"); |
||||
//Add our custom mime-type format |
||||
exclient.Options.MimeInputTypes.Add("foo/bar", CodedInputStream.CreateInstance); |
||||
exclient.Options.MimeOutputTypes.Add("foo/bar", CodedOutputStream.CreateInstance); |
||||
ISearchService client = new SearchService(exclient); |
||||
|
||||
//now the client has a real, typed, interface to work with: |
||||
SearchResponse result = client.Search(SearchRequest.CreateBuilder().AddCriteria("Test").Build()); |
||||
Assert.AreEqual(1, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
//The test part of this, call the only other method |
||||
result = |
||||
client.RefineSearch( |
||||
RefineSearchRequest.CreateBuilder().SetPreviousResults(result).AddCriteria("Refine").Build()); |
||||
Assert.AreEqual(2, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
Assert.AreEqual("Refine", result.ResultsList[1].Name); |
||||
Assert.AreEqual("http://refine.com", result.ResultsList[1].Url); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test] |
||||
public void TestServerWithUriFormat() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes("?Criteria=Test&Criteria=Test+of%20URI")); |
||||
MemoryStream output = new MemoryStream(); |
||||
|
||||
//Call the server |
||||
wire.Execute("Search", |
||||
MessageFormatOptions.ContentFormUrlEncoded, input, |
||||
MessageFormatOptions.ContentTypeProtoBuffer, output |
||||
); |
||||
|
||||
SearchResponse result = SearchResponse.ParseFrom(output.ToArray()); |
||||
Assert.AreEqual(2, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
|
||||
Assert.AreEqual("Test of URI", result.ResultsList[1].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[1].Url); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test, ExpectedException(typeof(ArgumentOutOfRangeException))] |
||||
public void TestInvalidMimeType() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
MemoryStream input = new MemoryStream(); |
||||
MemoryStream output = new MemoryStream(); |
||||
|
||||
//Call the server |
||||
wire.Execute("Search", |
||||
"bad/mime", input, |
||||
MessageFormatOptions.ContentTypeProtoBuffer, output |
||||
); |
||||
Assert.Fail(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Test sending and recieving messages via text/json |
||||
/// </summary> |
||||
[Test] |
||||
public void TestDefaultMimeType() |
||||
{ |
||||
ExampleHttpServer server = new ExampleHttpServer(new ExampleSearchImpl()); |
||||
|
||||
//obviously if this was a 'real' transport we would not use the server, rather the server would be listening, the client transmitting |
||||
IHttpTransfer wire = server; |
||||
|
||||
|
||||
MemoryStream input = new MemoryStream(new SearchRequest.Builder().AddCriteria("Test").Build().ToByteArray()); |
||||
MemoryStream output = new MemoryStream(); |
||||
|
||||
//With this default set, any invalid/unknown mime-type will be mapped to use that format |
||||
server.Options.DefaultContentType = MessageFormatOptions.ContentTypeProtoBuffer; |
||||
|
||||
wire.Execute("Search", |
||||
"foo", input, |
||||
"bar", output |
||||
); |
||||
|
||||
SearchResponse result = SearchResponse.ParseFrom(output.ToArray()); |
||||
Assert.AreEqual(1, result.ResultsCount); |
||||
Assert.AreEqual("Test", result.ResultsList[0].Name); |
||||
Assert.AreEqual("http://search.com", result.ResultsList[0].Url); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@ |
||||
Current task list (not in order) |
||||
|
||||
- Remove multifile support |
||||
- Docs |
||||
- Clean up protogen code |
||||
- Avoid using reflection for messages which don't need it (is this |
||||
possible?) |
||||
- Bring service generation into line with Java |
||||
- Build protoc as a dll and use directly from protogen |
||||
- Check copyright is everywhere |
||||
- Work out how to unit test Silverlight code |
||||
- Reformat code |
||||
- Change generated format |
||||
- Add regions to copyright |
||||
- Build and publish binaries |
||||
- Work out why the Compact Framework 3.5 build fails under VS2010 |
Loading…
Reference in new issue