How do I add new endpoints from Service Stack plugin? - c#

I am new to Service Stack, and am creating a plugin library for a Service Stack application we have.
Currently I have this class
public class MyPlugin : IPlugin {
public void Register(IAppHost appHost){
appHost.Routes.Add<MyPluginRequest>("/myendpoint", ApplyTo.Get);
}
}
When I add a breakpoint and walk through it, the code it getting called and Ideally the endpoint is being registered. But when the metadata page pulls up, the endpoint isn't listed and I am unable to navigate to the /myendpoint url.
This is the service that I have but it doesn't seem to be visible to the Api.
public class MyPluginService : Service {
public MyPluginResponse Get(MyPluginRequest request){
///... implementation details
}
}
UPDATE
I added this code to the Register Function:
appHost.GetPlugin<MetadataFeature>().AddPluginLink("myendpoint/", "endpoint custom");
So it will appear on the MetaData page, but when navigating to the link I am still getting an error
Unable to resolve service 'MyPluginRequest'

The Routes.Add API is only for registering custom routes for existing Services. If you want to dynamically register a Service you need to use RegisterService<T> API instead and specify the serviceType, e.g:
public class MyPlugin : IPlugin
{
public void Register(IAppHost appHost)
{
appHost.RegisterService<MyPluginService>("/myendpoint");
}
}
The AddPluginLink only adds the link to the metadata page:
appHost.GetPlugin<MetadataFeature>()
.AddPluginLink("/myendpoint", "My Custom Endpoint");

Related

How can I override or add an attribute to a method in a separate class so that refreshing a WCF service doesn't blow away my changes?

I have many WCF services that I'm wrapping with a proxy and I use the automatically generated contract classes for each service.
I see there are some stubs (ex. static partial void ConfigureEndpoint) that I can put in a separate class, but I've made other contract changes that get blown away when I update/refresh the WCF service. I'm very new to C#/ASP.NET-Core for some context.
A sample change in the contract is below where I added an attribute to default the company...how can I persist this attribute somehow through WCF refreshes?
[DefaultValue(Constants.DefaultCompany), Required] // I added this because I want to default a company
public string Company
{
get
{
return this.companyField;
}
set
{
this.companyField = value;
}
}
Another sample change I made was changing public to internal for this method because I don't want it displayed in Swagger and this field is a constant. When I refresh the WCF it comes back as public.
internal string PartitionKey // I changed public to internal
{
get
{
return this.partitionKeyField;
}
set
{
this.partitionKeyField = value;
}
}
Let's say you've added a service reference and Visual Studio generated a proxy called MyServiceClient. It might look a little like this:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class MyServiceClient : System.ServiceModel.ClientBase<MyService>
{
As you have found, if you modify MyServiceClient, your modifications will get overwritten if you refresh the service reference. To get around this, do not modify it directly. Instead, subclass it.
public class MyModifiedServiceClient : MyServiceClient
{
//Make changes here
}
Now in the rest of your c#, instead of using MyServiceClient, always use MyModifiedServiceClient. The derived class will not get overwritten when you refresh the service reference.

Blazor: InvalidOperationException while attempting to activate custom service

I am testing out Blazor and now trying to get a grip regarding services and custom services.
The problem is I get this error message when starting the Blazor application:
WASM: System.InvalidOperationException: Unable to resolve service for
type 'Blazor.Extensions.Storage.Interfaces.IStorage' while attempting
to activate 'BlazorTest.Services.MyLocalStorage'.
My own custom service MyLocalStorage requires another service to access the browsers local storage; in this case I am using Blazor.Extensions.Storage
According to this page on learn.microsoft.com, a custom service that depends on another service needs to have a constructor to support it: "Constructor injection must be used instead. Required services are added by adding parameters to the service's constructor. When dependency injection creates the service, it recognizes the services it requires in the constructor and provides them accordingly."
So, my ConfigureServices in Startup.cs looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddStorage(); // <-- extension method for Blazor.Extensions.Storage
services.AddSingleton<IMyLocalStorage, MyLocalStorage>();
}
and my custom service:
public interface IMyLocalStorage
{
Task<string> GetAuthToken();
Task<string> GetDeviceUUID();
Task SetAuthToken(string authToken);
Task SetDeviceUuid(string deviceUuid);
}
public class MyLocalStorage : IMyLocalStorage
{
private readonly IStorage storage;
public MyLocalStorage(IStorage storage)
{
this.storage = storage;
}
// bla bla implementation
}
I thought this was the only thing required, but it still fails as can be seen above.
Note that if I skip my own custom serivce and use the Blazor.Extensions.Storage package directly, it works without any issues.
Im running VS2019 Preview 16.2.0 and .NET Core 3.0.0.
If you take a look at the Blazor Storage code here you can see it does not register the IStorage interface.
Further inspection of the SessionStorage and LocalStorage classes shows that both implement IStorage so even if you did register IStorage you would need to clarify which class you want to inject.
It looks like you need to inject SessionStorage or LocalStorage in your constructor instead.
public class MyLocalStorage : IMyLocalStorage
{
private readonly LocalStorage storage;
public MyLocalStorage(LocalStorage storage)
{
this.storage = storage;
}
// bla bla implementation
}

Disable metadata exchange without using web.config

I am developing a single-tenant web application that will be deployed in client data centers and for security reasons we would like to disable the metadata exchange on the applications WCF services. Is it possible to do this this programatically within our service application or another mechanism besides the web.config? We want to prevent more technically minded clients from going to the web.config and turning metadata exchange back on.
You can disable the metadata exchange programmatically by setting the HttpGetEnabled/HttpsGetEnabled to false.
First, Create a derive host from ServiceHost.
public class DerivedHost : ServiceHost
{
public DerivedHost( Type t, params Uri baseAddresses ) :
base( t, baseAddresses )
{
DisableMetadataExchange();
}
private void DisableMetadataExchange()
{
var metadata = Description.Behaviors.Find<ServiceMetadataBehavior>();
if metadata != null)
{
// This code will disable metadata exchange
metadata .HttpGetEnabled = false;
metadata .HttpsGetEnabled = false;
}
}
}
Second, Create a derived factory from ServiceHostFactory.
public class DerivedFactory : ServiceHostFactory
{
public override ServiceHost CreateServiceHost( Type t, Uri[] baseAddresses )
{
return new DerivedHost( t, baseAddresses );
}
}
Third, Create or Edit your your svc file Markup and apply your derived factory.
<% #ServiceHost Factory=”DerivedFactory” Service=”MyService” %>
Fourth, Test your service in the browser and you should see a message contain "Metadata publishing for this service is currently disabled".
If want more details about this implementation kindly visit this link.
Yes. If you code your WCF service as "self describing", which basically means using a WCF intercept layer to handle all the incoming requests to an endpoint, you can just return null from the MEX request.
To make this work is a bit tricky but in my experience leads to a much cleaner implementation than all those voluminous web.config entries. This is described here WCF Configuration without a config file.

ninject error for Ninject.ActivationException

I have ASP.NET Web Application and added dll to the project.
I glue it I chose Ninject Ioc.
Because Web Application must have default constructor I decided to glue it in following way:
public IPlayerDb PlayerDb { get; set; }
public Logon()
{
Global.Kernel.Inject(this);
}
IPlayerDb is in external DLL library 'Contracts.dll'
PlayerDb class implemented IPlayerDb is in other dll : 'DataAccess.dll'
In DataAccess.dll there is class making glueing :
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<IDbConfig>().To<DbConfig>();
Bind<IPlayerDb>().To<PlayerDb>();
}
}
It's OK when I use my project after Visual Studio restarts (and IIS express I guess also).
But if I start to debug the application again it makes me following Error Message:
Error activating IPlayerDb
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IPlayerDb into property PlayerDb of type Logon
1) Request for logon_aspx
An exception of type 'Ninject.ActivationException' occurred in Ninject.dll but was not handled in user code
So, what's wrong with it. Seems I did everything by manual. Advice needed.

How to add SoapExtension attribute to generated web service client proxy without modifying the generated class?

I have created a SoapExtension class to capture the soap request and response from specific web service calls. In order to put this SoapExtension into effect, I have to add an attribute to the method in the generated proxy client.
For example, I've added the AuditSoapCapture attribute to this method:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://blahblah.com/webservices/AddressSearch", RequestNamespace = "http://blahblah.com/webservices/", ResponseNamespace = "http://blahblah.com/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[blahblah.TriadLite.Core.AuditSoapCapture]
public System.Data.DataSet AddressSearch(string HouseNumber, string StreetName, string ZipCode) {
object[] results = this.Invoke("AddressSearch", new object[] {
HouseNumber,
StreetName,
ZipCode});
return ((System.Data.DataSet)(results[0]));
}
I am looking for a way to add this attribute to specific methods without modifying the generated client proxy, as they will get lost when we regenerate. Can I do this in a another partial class or interface or some other way?
Thanks!
Unfortunately, you'll need to modify the proxy code. The other possibilities you mention will not work - a parial class will not overwrite existing functionality, and there is no way that I'm aware of getting an interface to do what you need (compounded by the fact that there is no way to even let the proxy generator know that you intend to implement an interface).
Something that I've done in the past, in a situation where you have access to the source of the webservice, is to write a little app that will parse the code (as text) in the .asmx.cs file of the webservice to extract the names of all the methods that are tagged with [WebMethod]. Then the app "fixes up" the References.cs by inserting appropriate attributes onto the proxied methods, based on some settings file or somesuch. This works well because the naming conventions in the proxy map very neatly to the method names in the original service.
I may just end up injecting my SoapExtension by putting it into the Web.config. This will cause it to be run on every WS call without a client proxy method attribute. Then, I will modify the SoapExtension to look up the called WS method name on a list, and if it is on the list, then do the rest of the SoapExtension logic. I figure the hit on the list in this small volume application isn't going to kill performance.
6 years ago this was posted... So not sure if this will help anyone at this point.
I ran into something similar with a call to an old SOAP web service that had a dynamically generated proxy class that we didn't want to modify as it was auto-generated from the wsdl by the project. In order to solve this problem here is what we did.
The proxy class generated by wsdl.exe is a partial class. We extended this class like so to add a property with the information we wanted to access in the soapextension. You can add as many properties as you want...
partial class mysoapwebservice
{
public string myproperty{ get; set; }
}
in the web.config we registered the soap extension globaly on the project
<webServices>
<soapExtensionTypes>
<add type="MySoapExtension" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
In the code were we created the web service object 'mysoapwebservice' we set the value of the property we needed.
In the soapextension you can get a reference to the web service that was called as well as the values. You can also determine the method call.
`
public class MySoapExtension: SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
{
// web service client object
var webserviceobject= ((SoapClientMessage)message).Client;
// method from web service that was called
var calledMethod = (SoapClientMessage)message).MethodInfo;
// checked the client type of webserviceobject and
//added method / property specific logic here
}
}
}
// other soap extension code
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CriptoExtensionAttribute : SoapExtensionAttribute
[CriptoExtension]
public partial class MainService{

Categories

Resources