dot_net_services 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,282 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'net/http'
4
+
5
+ module DotNetServices
6
+
7
+ # The Session class is used for communicating with endpoints of .NET Services bus.
8
+ #
9
+ # == Usage examples
10
+ #
11
+ # A Session instance represents a .NET Services bus endpoint. Typically, you create it by calling Session#open
12
+ # and then exchange HTTP messages using methods like #get, #post, etc. It looks like this:
13
+ #
14
+ # Send a GET with no parameters:
15
+ #
16
+ # session = Session.open('/MySolution/MyService', :username => 'MySolution', :password => 'my_password')
17
+ # get_response = session.get
18
+ # # ... process response, which is a Net::HTTP::Response instance
19
+ #
20
+ # Send a GET with ?age=21&sex=Male query string:
21
+ #
22
+ # get_with_query_response = session.get :age => 21, :sex => "Male"
23
+ #
24
+ # Send a POST with name=Joe&email=joe@the_plumber.com (URL-encoded form) as a body:
25
+ #
26
+ # post_response = session.post :name => 'Joe', :email => 'joe@the_plumber.com'
27
+ #
28
+ # So far, Session API is similar to Net::HTTP::Session. Which is the whole point of the REST style
29
+ # communication - it is all just HTTP! However, there is one small twist. HTTP::Session represents a server
30
+ # (host and port). DotNetServices::Session represents a service endpoint. Which is a <b>URL</b>, not a server. In
31
+ # fact, all .NET Services endpoints have the same server, servicebus.windows.net. So an endpoint address is really
32
+ # just a path on that server.
33
+ #
34
+ # And sometimes you need to send requests to a path under the endpoint. For example, to update the name of customer
35
+ # #12345, you would do a POST to /MySolution/Customer/12345 with &name=Dave body. Creating a new Session for that is
36
+ # both counterintuitive and expensive (see the Details section below). For this reason, DotNetServices::Session has
37
+ # methods like post_to_url:
38
+ #
39
+ # result = session.post_to_url(12345, :name => 'Dave')
40
+ #
41
+ # == Details
42
+ #
43
+ # When a session is created, it's given the URL of an endpoint (that looks like /SolutionName/path/to/service), and
44
+ # username / password. These are <b>solution's</b> username and password, needed to prove to the bus that
45
+ # your consumer is a part of this solution. If the solution allows anonymous access, username / password are not
46
+ # necessary.
47
+ #
48
+ # When a session is opened (or is asked to send a first request to the endpoint), the session authenticates itself
49
+ # to the .NET Services using Identity Service [http://accesscontrol.windows.net], and obtains a security token from it.
50
+ #
51
+ # Security token is a Base64-encoded string. Unless an endpoint allows unauthenticated access, any request that comes
52
+ # to the endpoint must have this security token attached to it (as X-MS-Identity-Token HTTP header).
53
+ # DotNetServices::Session takes care of this responsibility, as well as renewing stale tokens.
54
+ #
55
+ # Session also has methods get_from_relay and post_to_relay, that are used for communicating to the .NET Services
56
+ # bus management endpoint. These methods (createmb, retrieve, query) are used by MessageBuffer, an application normally
57
+ # shouldn't need to use them directly.
58
+ #
59
+ # == Guidelines
60
+ #
61
+ # Obtaining a security token is an expensive operation, so it is <b>not</b> recommended to create a new instance of
62
+ # a Session for every outgoing request to the endpoint. It's better to use one Session instance per endpoint.
63
+ # Session takes care of expiring security tokens autoimatically, so Session instances don't go stale even after long
64
+ # periods of inactivity.
65
+ class Session
66
+
67
+ attr_reader :authenticator
68
+
69
+ class << self
70
+ # Open a .Net Services session at the +endpoint+.
71
+ #
72
+ # If +auth_data+ is provided, authenticates the session with
73
+ # the identity service using it. In this version, +auth_data+ should be a hash containing +:username+ and
74
+ # +:password+ keys. Other authentication mechanisms (InformationCard, X.509 certificates etc) that the Identity
75
+ # service provides are not exposed via a REST interface, therefore are not available to this library.
76
+ #
77
+ # If #open is called with a block, it passes the session instance as an argument to the block and returns the
78
+ # result of the block. If there is no block, session instance is returned instead.
79
+ def open(endpoint, auth_data = nil, &block)
80
+ Session.new(endpoint, auth_data).open(&block)
81
+ end
82
+ end
83
+
84
+ # Initialize a new .NET Session at the +endpoint+.
85
+ #
86
+ # If +auth_data+ is provided, remember it. Acquiring
87
+ # authentication token is postponed until it's needed.
88
+ def initialize(endpoint, auth_data=nil)
89
+ @endpoint_uri = setup_endpoint(endpoint)
90
+ @authenticator = Authentication.setup(auth_data)
91
+ end
92
+
93
+ # See DotNetServices::Session.open.
94
+ def open
95
+ authenticate
96
+ block_given? ? yield(self) : self
97
+ end
98
+
99
+ # Acquire a security token from the Identity Service.
100
+ #
101
+ # This method will do nothing if:
102
+ # * this session already holds a security token and the token has not expired yet, or
103
+ # * the session was created without auth_data (anonymous session)
104
+ def authenticate
105
+ @authenticator.authenticate
106
+ end
107
+
108
+ # Send a GET request to the .NET Services endpoint.
109
+ #
110
+ # If query options are provided, they should be a hash, and they are converted to a query string and attached to
111
+ # the GET request target URL.
112
+ # Thus, session.get(:foo => 'bar') sends a GET to #{endpoint}?foo=bar
113
+ def get(query_options=nil)
114
+ get_from_url(nil, query_options)
115
+ end
116
+
117
+
118
+ def get_from_url(url, query_options=nil)
119
+ uri = setup_query_string(url, query_options)
120
+ get_request = Net::HTTP::Get.new(uri.request_uri)
121
+ enhance_and_execute(get_request)
122
+ end
123
+
124
+ # Sends a GET to the service management endpoint.
125
+ #
126
+ # This is used by MessageBuffer for VMB management. Applications shouldn't need to use this method.
127
+ def get_from_relay(query_options=nil)
128
+ uri = setup_query_string(nil, query_options)
129
+ get_request = Net::HTTP::Get.new(uri.request_uri)
130
+ route_to_relay(get_request)
131
+ enhance_and_execute(get_request)
132
+ end
133
+
134
+ # Send a POST request to the .NET Services endpoint.
135
+ #
136
+ # If +data+ is a Hash it is converted to a URL-encoded form, otherwise it is placed in the post body without any
137
+ # conversion.
138
+ #
139
+ # +content_type+ by default is set to +application/x-www-form-urlencoded+, which is appropriate when +data+ is a
140
+ # Hash. In any other case, you should specify +content_type+ explicitly.
141
+ def post(data=nil, content_type='application/x-www-form-urlencoded')
142
+ post_to_url("", data, content_type)
143
+ end
144
+
145
+ # Sends a POST request to a path below .NET Services endpoint.
146
+ #
147
+ # If an application neeeds to send a POST to a service that uses URL to receive data, it should use this method
148
+ # instead of creating a new session for every new request. For example, if a service endpoint is called
149
+ # /Solution/Maps, and it's URL template is /Solution/Maps/*country*/*province*/*city*, a way to create a map of
150
+ # Calgary would be:
151
+ #
152
+ # session.post_to_url('/Canada/Calgary', map_data, content_type=...)
153
+ def post_to_url(url, data=nil, content_type='application/x-www-form-urlencoded')
154
+ post_request = Net::HTTP::Post.new(@endpoint_uri.path + url.to_s)
155
+ if data
156
+ post_request.content_type = content_type
157
+ if content_type == 'application/x-www-form-urlencoded'
158
+ post_request.form_data = data
159
+ else
160
+ post_request.body = data
161
+ end
162
+ end
163
+ enhance_and_execute(post_request)
164
+ end
165
+
166
+
167
+ # Sends a POST to the service management endpoint.
168
+ #
169
+ # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#keep_alive.
170
+ def post_to_relay(data=nil, content_type='application/x-www-form-urlencoded')
171
+ post_request = Net::HTTP::Post.new(@endpoint_uri.path)
172
+
173
+ if data
174
+ post_request.content_type = content_type
175
+ if content_type == 'application/x-www-form-urlencoded'
176
+ post_request.form_data = data
177
+ else
178
+ post_request.body = data
179
+ end
180
+ end
181
+ route_to_relay(post_request)
182
+ enhance_and_execute(post_request)
183
+ end
184
+
185
+ # Create a new message buffer (sends an X-CREATEMB to the service management endpoint).
186
+ #
187
+ # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#open.
188
+ def createmb
189
+ request = Net::HTTP::CreateMB.new(@endpoint_uri.path)
190
+ route_to_relay(request)
191
+ enhance_and_execute(request)
192
+ end
193
+
194
+ # Subscribe a message buffer to a virtual endpoint (sends an X-SUBSCRIBE to the VMB management endpoint).
195
+ #
196
+ # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#open.
197
+ def subscribe(request_options)
198
+ uri = setup_query_string(nil, request_options)
199
+ request = Net::HTTP::Subscribe.new(uri.request_uri)
200
+ route_to_relay(request)
201
+ enhance_and_execute(request)
202
+ end
203
+
204
+ # Unsubscribe a message buffer from a virtual endpoint (sends an X-UNSUBSCRIBE to the VMB management endpoint).
205
+ #
206
+ # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#open.
207
+ def unsubscribe(request_options)
208
+ uri = setup_query_string(nil, request_options)
209
+ request = Net::HTTP::Unsubscribe.new(uri.request_uri)
210
+ route_to_relay(request)
211
+ enhance_and_execute(request)
212
+ end
213
+
214
+ # Retrieve the next message from the message buffer (sends an X-RETRIEVE to the service management endpoint).
215
+ #
216
+ # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#poll.
217
+ def retrieve(query_options={})
218
+ query_options = stringify_and_downcase_keys(query_options)
219
+ query_options['timeout'] ||= 15
220
+ uri = setup_query_string(nil, query_options)
221
+ request = Net::HTTP::Retrieve.new(uri.request_uri)
222
+ route_to_relay(request)
223
+ enhance_and_execute(request)
224
+ end
225
+
226
+
227
+ # Delete an endpoint (sends a DELETE to the service management endpoint).
228
+ #
229
+ # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#delete.
230
+ def delete
231
+ request = Net::HTTP::Delete.new(@endpoint_uri.path)
232
+ route_to_relay(request)
233
+ enhance_and_execute(request)
234
+ end
235
+
236
+ # The URL of a .NET services endpoint this Session is connected to.
237
+ def endpoint
238
+ @endpoint_uri.to_s
239
+ end
240
+
241
+ private
242
+
243
+ def enhance_and_execute(request)
244
+ @authenticator.enhance(request)
245
+ DotNetServices.proxy.start(@endpoint_uri.host, @endpoint_uri.port) { |http| http.request(request) }
246
+ end
247
+
248
+ def route_to_relay(request)
249
+ request['X-Process-At'] = 'http://schemas.microsoft.com/ws/2007/08/connect/roles/relay'
250
+ end
251
+
252
+ def setup_endpoint(endpoint)
253
+ if endpoint !~ /^http(s?):\/\//
254
+ endpoint = '/' + endpoint unless endpoint[0] == ?/
255
+ endpoint = DotNetServices.root_url + endpoint
256
+ end
257
+ endpoint += '/' unless endpoint[-1] == ?/
258
+ URI.parse(endpoint)
259
+ end
260
+
261
+ def setup_query_string(url, query_options)
262
+ if url && !url.empty?
263
+ uri = @endpoint_uri + url.to_s
264
+ else
265
+ uri = @endpoint_uri.dup
266
+ end
267
+
268
+ if query_options
269
+ query = query_options.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
270
+ uri.query = query
271
+ end
272
+ uri
273
+ end
274
+
275
+ def stringify_and_downcase_keys(options)
276
+ new_options = {}
277
+ options.each { |key, value| new_options[key.to_s.downcase] = value unless value.nil? }
278
+ new_options
279
+ end
280
+
281
+ end
282
+ end
@@ -0,0 +1,143 @@
1
+ require 'dot_net_services/session'
2
+ require 'dot_net_services/authentication'
3
+ require 'dot_net_services/error'
4
+ require 'dot_net_services/message_buffer'
5
+ require 'net/http/create_mb'
6
+ require 'net/http/retrieve'
7
+ require 'net/http/subscribe'
8
+
9
+ # DotNetServices is the top-level namespace of <b>.NET Services for Ruby</b>, Ruby interoperability layer for
10
+ # .NET Services plain HTTP (REST) API.
11
+ #
12
+ # == .NET Services
13
+ #
14
+ # Since you are reading this, you probably already know that .NET Services is a Microsoft product, described as the
15
+ # "Internet Services Bus", a messaging bus in the cloud. Like any other messaging bus, it helps services and consumers
16
+ # to communicate with each other. Further information on .NET Services can be found on MSDN:
17
+ # http://go.microsoft.com/fwlink/?LinkID=129428.
18
+ #
19
+ # While .NET Services primarily target .NET platform, non-Microsoft software is also catered for,
20
+ # by providing open protocols for most of the bus functionality, in both SOAP/WS-* and plain HTTP style. The latter
21
+ # is structured in a way that makes it easy to implement REST interactions over the bus, including both
22
+ # synchronous and asynchronous semantics. .NET Services bus doesn't force an application to use REST, any
23
+ # other kind of plain HTTP protocol can be routed through it, too.
24
+ #
25
+ #
26
+ # == Functionality
27
+ #
28
+ # This library is a simple Ruby wrapper for .NET Services plain HTPP (REST) APIs. Current version allows Ruby
29
+ # developers to build consumers of synchronous RESTful services (implemented as .NET WCF services, using
30
+ # webHttpRelayBinding, provided by the .NET Services SDK). You can also exchange messages between Ruby processes via
31
+ # Volatile Message Buffers (VMBs), which are .NET Services mechanism for asynchronous communications.
32
+ #
33
+ # .NET Services for Ruby looks like Net::HTTP API from the standard library, but deals with authentication,
34
+ # VMB management and message retrieval.
35
+ #
36
+ # Since this is a 0.1.0 version of an interoperability layer for a PDC version of a bus, a few things are missing.
37
+ #
38
+ # Most notably, with this version you still can not:
39
+ # * communicate with WCF services bound by anything other than webHttpRelayBinding.
40
+ # * communicate with the bus via WS-* protocols.
41
+ # * communicate with a WCF-based service via a VMB. At least, not until .NET Services SDK adds a WCF binding for
42
+ # REST via VMB. Once it's available, we should be able to work with it.
43
+ # * use VMB pub-sub and multicast functionality
44
+ # * use Workflow Services
45
+ # * use Identity Service as a dfederated identity provider for end-users
46
+ #
47
+ # == Usage examples
48
+ #
49
+ # Say, you are a cellphone dealer. You have a Point of Sale web application, written in Rails. It sells cellphones.
50
+ # The phones you sell are operated by a phone company, which offers a .NET Services solution (group of services in
51
+ # the .NET Services world), called Dealership. It includes two services, Customer and Provisioning.
52
+ #
53
+ # Customer service is a RESTful service endpoint, implemented by WCF service with a webHttpRelayBinding. It's listening
54
+ # on /Customer URL, and provides the usual CRUD functionality for managing customers.
55
+ #
56
+ # Provisioning service endpoint is a VMB. Coincidentally, it's also written in Ruby! :) When a customer buys a new phone,
57
+ # provisioning application should activate the phohe on the network, so that the customer can actually make calls with it.
58
+ # Activation can take several minutes, even hours, and we don't want the point of sale terminal to hang until it's over.
59
+ # Hence the use of a VMB as an asynchronous communication device.
60
+ #
61
+ # To create a customer, point of sale app needs to post a URL-encoded form to a webHttpRelayBinding endpoint. That's
62
+ # where you need to use a DotNetServices::Session class:
63
+ #
64
+ # require 'dotnetservices'
65
+ # session = DotNetServices::Session.open("/Dealership/Customer", :username => 'Dealership', :password => '_password')
66
+ # session.post :first_name => 'John', :last_name => 'Doe'
67
+ #
68
+ # Posting a message to a Provisioning endpoint would actually look the same:
69
+ #
70
+ # session = DotNetServices::Session.open("/Dealership/Provisioning", :username => 'Dealership', :password => '_password')
71
+ # session.post :phone_number => '555 888-8888'
72
+ #
73
+ # DotNetServices::MessageBuffer is needed by the Provisioning *service* (and not the client), to register the VMB and
74
+ # retrieve messages from it. Usage typically looks like this:
75
+ #
76
+ # buffer = DotNetServices::MessageBuffer.new("/Dealership/Provisioning",
77
+ # :username => 'Dealership', :password => '_password')
78
+ # buffer.open_and_poll do |message|
79
+ # ... process incoming messages ...
80
+ # end
81
+ #
82
+ # This code will check that the VMB exists, create one if necessary, and continuously poll it for new messages. Whenever
83
+ # a new message is sent to VMB, MessageBuffer#open_and_poll retrieves it and invokesthe block, passing it a
84
+ # Net::HTTP::Request instance that looks exactly like what the sender originally sent to the VMB. Nice and easy.
85
+ #
86
+ # To understand and use .NET Services for Ruby, you should probably also read the documentation for the two classes
87
+ # mentioned above: DotNetServices::Session and DotNetServices::MessageBuffer.
88
+ #
89
+ # Happy bussing!
90
+ module DotNetServices
91
+
92
+ class << self
93
+
94
+ # The name of the host providing DotNetServices relay services.
95
+ def relay_host
96
+ "servicebus.windows.net"
97
+ end
98
+
99
+ # The name of the host providing DotNetServices identity services.
100
+ def identity_host
101
+ 'accesscontrol.windows.net'
102
+ end
103
+
104
+ # The root URL used for exposing services.
105
+ def root_url
106
+ "http://#{relay_host}/services"
107
+ end
108
+
109
+ # Host and port of the bus endpoint.
110
+ def host_port
111
+ return @host_port if @host_port
112
+ uri = URI.parse(root_url)
113
+ @host_port = [uri.host, uri.port]
114
+ @host_port
115
+ end
116
+
117
+ # Use an HTTP proxy to connect to .NET Services
118
+ #
119
+ # If you call this method, all subsequent communications with .NET Services will use an HTTP proxy.
120
+ # You must given hostname and password #use proxy
121
+ # DotNetServices.use_proxy()
122
+ def use_proxy(proxy_host, proxy_port, proxy_user = nil, proxy_password = nil)
123
+ @proxy = Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_password)
124
+ end
125
+
126
+ # An HTTP proxy to connect through.
127
+ #
128
+ # Defaults to Net::HTTP (direct connection without proxy). To set a proxy, see #use_proxy.
129
+ def proxy
130
+ @proxy || Net::HTTP
131
+ end
132
+
133
+ # TODO implement!
134
+ def logger
135
+ if RAILS_ENV
136
+ nil
137
+ else
138
+ @logger ||= nil
139
+ end
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,14 @@
1
+ module Net # :nodoc:
2
+ class HTTP # :nodoc:
3
+ # Custom request type X-CREATEMB for creating message buffers on
4
+ # the .NET Service Bus.
5
+ #
6
+ # This request should not be used directly. Use
7
+ # DotNetServices::Session#createmb instead.
8
+ class CreateMB < HTTPRequest
9
+ METHOD = "X-CREATEMB"
10
+ REQUEST_HAS_BODY = false
11
+ RESPONSE_HAS_BODY = true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Net # :nodoc:
2
+ class HTTP # :nodoc:
3
+ # Custom X-RETRIEVE for retrieving messages from the .NET Services
4
+ # message buffer.
5
+ #
6
+ # This request should not be used directly. Use
7
+ # DotNetServices::Session#retrieve instead.
8
+ class Retrieve < HTTPRequest
9
+ METHOD = "X-RETRIEVE"
10
+ REQUEST_HAS_BODY = false
11
+ RESPONSE_HAS_BODY = true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Net # :nodoc:
2
+ class HTTP # :nodoc:
3
+ # Custom request type X-CREATEMB for creating message buffers on
4
+ # the .NET Service Bus.
5
+ #
6
+ # This request should not be used directly. Use
7
+ # DotNetServices::Session#createmb instead.
8
+ class Subscribe < HTTPRequest
9
+ METHOD = "X-SUBSCRIBE"
10
+ REQUEST_HAS_BODY = false
11
+ RESPONSE_HAS_BODY = true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Net # :nodoc:
2
+ class HTTP # :nodoc:
3
+ # Custom request type X-CREATEMB for creating message buffers on
4
+ # the .NET Service Bus.
5
+ #
6
+ # This request should not be used directly. Use
7
+ # DotNetServices::Session#createmb instead.
8
+ class Unsubscribe < HTTPRequest
9
+ METHOD = "X-UNSUBSCRIBE"
10
+ REQUEST_HAS_BODY = false
11
+ RESPONSE_HAS_BODY = true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ namespace DotNetServicesRuby
2
+ {
3
+ using System.ServiceModel;
4
+
5
+ [ServiceBehavior(Name = "SyndicationService", Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]
6
+ class AnonymousResourceService : ResourceService
7
+ {
8
+ }
9
+ }
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <configuration>
3
+ <system.serviceModel>
4
+
5
+ <bindings>
6
+ <!-- Application Binding -->
7
+ <webHttpRelayBinding>
8
+ <binding name="default" />
9
+ </webHttpRelayBinding>
10
+ </bindings>
11
+
12
+ <services>
13
+ <!-- Application Service -->
14
+ <service name="DotNetServicesRuby.ResourceService"
15
+ behaviorConfiguration="default">
16
+ <endpoint contract="DotNetServicesRuby.ResourceContract"
17
+ binding="webHttpRelayBinding"
18
+ bindingConfiguration="default"
19
+ address="" />
20
+ </service>
21
+ </services>
22
+
23
+ <behaviors>
24
+ <serviceBehaviors>
25
+ <behavior name="default">
26
+ <serviceDebug httpHelpPageEnabled="false" httpsHelpPageEnabled="false" />
27
+ </behavior>
28
+ </serviceBehaviors>
29
+ </behaviors>
30
+
31
+ </system.serviceModel>
32
+ </configuration>
@@ -0,0 +1,37 @@
1
+ namespace DotNetServicesRuby
2
+ {
3
+ using System;
4
+ using System.Runtime.Serialization;
5
+ using System.ServiceModel;
6
+ using System.ServiceModel.Web;
7
+ using System.ServiceModel.Channels;
8
+
9
+ [ServiceContract]
10
+ [ServiceBehavior]
11
+ class PlainTextService
12
+ {
13
+ [OperationContract(Action="*", ReplyAction="*")]
14
+ [WebInvoke(BodyStyle=WebMessageBodyStyle.Bare)]
15
+ //public string Process(string foo)
16
+ //{
17
+ // return "hi mom";
18
+ //}
19
+
20
+ public Message Process(Message message)
21
+ {
22
+ var httpRequest = (HttpRequestMessageProperty)(message.Properties["httpRequest"]);
23
+
24
+ var query = httpRequest.QueryString;
25
+ var verb = httpRequest.Method;
26
+ var body = "";
27
+
28
+ Message response = Message.CreateMessage(MessageVersion.None, "GETRESPONSE", "hi, mom");
29
+
30
+ HttpResponseMessageProperty responseProperty = new HttpResponseMessageProperty();
31
+ responseProperty.Headers.Add("Content-Type", "text/plain");
32
+ response.Properties.Add(HttpResponseMessageProperty.Name, responseProperty);
33
+ return response;
34
+ }
35
+
36
+ }
37
+ }
@@ -0,0 +1,49 @@
1
+ namespace DotNetServicesRuby
2
+ {
3
+ using System;
4
+ using System.ServiceModel;
5
+ using System.ServiceModel.Web;
6
+ using System.ServiceModel.Description;
7
+ using Microsoft.ServiceBus;
8
+
9
+ class Program
10
+ {
11
+ static void Main(string[] args)
12
+ {
13
+
14
+ System.Console.WriteLine("Enter solution name: ");
15
+ var solutionName = System.Console.ReadLine();
16
+ System.Console.WriteLine("Enter password for " + solutionName + " solution:");
17
+ var password = System.Console.ReadLine();
18
+
19
+ var behavior = new TransportClientEndpointBehavior();
20
+ behavior.CredentialType = TransportClientCredentialType.UserNamePassword;
21
+ behavior.Credentials.UserName.UserName = solutionName;
22
+ behavior.Credentials.UserName.Password = password;
23
+
24
+ var address = new Uri(String.Format("http://{0}/services/{1}/TestService/", ServiceBusEnvironment.DefaultRelayHostName, solutionName));
25
+ var host = new ServiceHost(typeof(ResourceService), address);
26
+ host.Description.Endpoints[0].Behaviors.Add(behavior);
27
+ host.Open();
28
+
29
+ //var anonymousAddress = new Uri(String.Format("http://{0}/services/{1}/AnonymousTestService/", ServiceBusEnvironment.DefaultRelayHostName, solutionName));
30
+ //var anonymousHost = new ServiceHost(typeof(AnonymousResourceService), anonymousAddress);
31
+ //anonymousHost.Description.Endpoints[0].Behaviors.Add(behavior);
32
+ //anonymousHost.Open();
33
+
34
+ //var plainTextAddress = new Uri(String.Format("http://{0}/services/{1}/PlainTextTestService/", ServiceBusEnvironment.DefaultRelayHostName, solutionName));
35
+ //var plainTextHost = new WebServiceHost(typeof(PlainTextService), plainTextAddress);
36
+ //plainTextHost.Description.Endpoints[0].Behaviors.Add(behavior);
37
+ //plainTextHost.Open();
38
+
39
+ Console.WriteLine("Service address: " + address);
40
+ Console.WriteLine("Press [Enter] to exit");
41
+ Console.ReadLine();
42
+
43
+ host.Close();
44
+ //anonymousHost.Close();
45
+ //plainTextHost.Close();
46
+ }
47
+
48
+ }
49
+ }
@@ -0,0 +1,33 @@
1
+ using System.Reflection;
2
+ using System.Runtime.CompilerServices;
3
+ using System.Runtime.InteropServices;
4
+
5
+ // General Information about an assembly is controlled through the following
6
+ // set of attributes. Change these attribute values to modify the information
7
+ // associated with an assembly.
8
+ [assembly: AssemblyTitle("Service")]
9
+ [assembly: AssemblyDescription("")]
10
+ [assembly: AssemblyConfiguration("")]
11
+ [assembly: AssemblyCompany("")]
12
+ [assembly: AssemblyProduct("Service")]
13
+ [assembly: AssemblyCopyright("Copyright © 2006")]
14
+ [assembly: AssemblyTrademark("")]
15
+ [assembly: AssemblyCulture("")]
16
+
17
+ // Setting ComVisible to false makes the types in this assembly not visible
18
+ // to COM components. If you need to access a type in this assembly from
19
+ // COM, set the ComVisible attribute to true on that type.
20
+ [assembly: ComVisible(false)]
21
+
22
+ // The following GUID is for the ID of the typelib if this project is exposed to COM
23
+ [assembly: Guid("23fce5dd-8bf8-403c-b748-d24504e7c5c1")]
24
+
25
+ // Version information for an assembly consists of the following four values:
26
+ //
27
+ // Major Version
28
+ // Minor Version
29
+ // Build Number
30
+ // Revision
31
+ //
32
+ [assembly: AssemblyVersion("1.0.0.0")]
33
+ [assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,17 @@
1
+ namespace DotNetServicesRuby
2
+ {
3
+ using System;
4
+ using System.Runtime.Serialization;
5
+ using System.ServiceModel;
6
+ using System.ServiceModel.Web;
7
+ using System.ServiceModel.Channels;
8
+
9
+ [ServiceContract(Name = "ResourceContract", Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]
10
+ public interface ResourceContract
11
+ {
12
+ [OperationContract(Action = "*", ReplyAction = "*")]
13
+ Message Process(Message message);
14
+ }
15
+
16
+ public interface ResourceChannel : ResourceContract, IClientChannel { }
17
+ }