I'm working on a legacy ServiceStack application, and I'm trying to add a new endpoint. It's a servicestack 3 application. I created new Response, Request, and Service classes for it, like I've done countless times for other endpoints, but for some reason I can't seem to call it.
I even tried just copying previously existing files and rewriting them to fit my needs, but that didn't work either.
Here's my request:
[Route("/OSTicket/UpdateList", "POST")]
public class OSTicketUpdateListByDBIDRequest
{
public int DatabaseID { get; set; }
}
Here's my response:
public class OSTicketUpdateListResponse : IHasResponseStatus
{
public ResponseStatus ResponseStatus { get; set; }
}
And here's my service endpoint:
public OSTicketUpdateListResponse Post(OSTicketUpdateListByDBIDRequest request)
{
OSTicketUpdateListResponse response = new OSTicketUpdateListResponse();
response.ResponseStatus = new ResponseStatus();
response.ResponseStatus.ErrorCode = "200";
return response;
}
Do I need to register these files somewhere? I don't remember having to do that in the past, but it's very possible that I'm missing something. Whenever I POST to the application using DHC, I get a 404.
Figured it out. In my service declaration:
public class OSTicketService
I forgot to inherit Service.
Related
My intent is to create a payment processing service I can bolt onto the side of any website. My issue is injecting settings, such as a Stripe Public Key, a Paypal Merchant Id, and the specific url on the server to send the token and to charge stripe.
This is simplified for this question (and the Payments projects will end up being dll's), but the project structure looks like this:
The WebApp is the ASP.NET Core hosted Blazor WASM project template. WebApp.Client has dependencies on Payments.Shared and Payments.Ui while WebApp.Server has a dependency on Payments.Backend as well (for Stripe charge response etc models).
Since I want to use this Payments service on any site, and since these will be different for every site, I'll need to set the props in PaymentSettings.cs at startup.
Is there a way to do this? I only plan on using with Blazor WASM websites, if that matters.
I feel like I might be able to pass these settings down to the WebApp.Client through string[] args in Program.cs's Main method:
public static async Task Main(string[] args)
{
//omitted for brevity
//relevant line here
builder.Services
.AddSingleton(sp => new Payments.Shared.Infrastructure.PaymentSettings(args));
await builder.Build().RunAsync();
}
and then from there into the constructor for PaymentSettings.cs:
public class PaymentSettings
{
public PaymentSettings(string[] args)
{
//set props from args
}
public string PaypalMerchantId { get; set; }
public string StripeKey { get; set; }
public string ChargeStripeUrl { get; set; }
}
But I don't see any way to do this from the WebApp.Server project.
Maybe I'm overthinking this, I mean, if I can at least inject the base url of WebApp.Server into the Payments.Shared project, I can then run a get request for the rest of it.
Any help much appreciated.
I was overthinking it. Since it's all public info, I just hard-coded the info into Program.cs in the WebApp.Client:
public static async Task Main(string[] args)
{
//omitted for brevity
string stripeKey = "Hello dolly";
string paypalId = "How ye be";
string chargeStripeUrl = "https://all-about-dolly.com/chargeIt";
//relevant line here
builder.Services.AddSingleton(sp => new PaymentSettings
{
StripeKey = stripeKey,
PaypalMerchantId = paypalId,
ChargeStripeUrl = chargeStripeUrl
});
await builder.Build().RunAsync();
}
Might not be best practices, but it works for me.
I have an Angular (Angular 9) application as client and a ASP.NET WebApi as server.
The server has an additional Signalr2 interface.
First thing is I don't know if the server where my application will be installed supports websockets.
If not, my angular application would create an http request to the WEB API and get the response asynchrounus, so normal REST.
If the server supports websockets, I would like to do a websocket request from my client side and get the response from signalR.
The client side is clear, I would do some kind of HTTPClient abstraction to generate one or the other and wait for the response.
The other thing is, how can I call a Web APi method from my SignalRHub without using the .Net HttpClient?
And if I have to use the HttpClient, is the overhead so big, that doing a normal http request would result the same?
This could be my SignalR data:
public WebApiRequest{
public string HttpMethod{ get; set;}
public string Route{ get; set;}
public OrderedDictionary<string, object> Parameters{ get; set;}
public string Content{ get; set;}
}
And this the SignalR response data:
public WebApiResponse{
public int StatusCode{ get; set;}
public object Data{ get; set;}
}
This the Test Web Api Controller:
[RoutePrefix("api/test")]
[Authorize]
public class TestController : ApiController
{
[HttpPost]
[Route("calculate")]
public async Task<IHttpActionResult> Calculate(int id, Calculatedata calc)
{
return Ok(CalculateMyTestData(id, calc));
}
}
Now with the data from the signalr request I would like to call the 'Calculate' method of the 'TestController' and give the response as WebApiResponse back.
An idea, this is inside my Hub:
public void DoWebApirequest(WebApiRequest data)
{
var test = new TestController()
{
var method = GetHttpMethod(data.HttpMethod);
Request = new HttpRequestMessage(method , this.Context.Request.Url)
{
Content = new StringContent(data.Content, Encoding.UTF8, "application/json")
}
};
foreach (var contextHeader in this.Context.Headers)
{
test.Request.Headers.Add(contextHeader.Key, contextHeader.Value);
}
// Now fill the parameters and call the method you like by reflection...
test.Calculate(...);
}
Could this work?
First of all, I want to share my scenario what i want to build -
Scenario:
I am building a client app using wpf. In some cases, I need to call a web service to get data from the server. In order to do this, I added a web reference using wsld url. And I created a ServiceManager class that will call service method. For security reason, I need to add some header info at soap xml request for example, UserToken, SAML Token and so on. I can this from my ServiceManager class. But I want to add another class which will be called before sending request to the server. In that class, I will do something like adding security header to soap xml request with request and then send it to the server.
I used SOAP Extension to fulfill my purpose and it works well. But the problem is, every-time I need to add annotation in Reference.cs (for each web service reference) file at top of the service method. I believe that there is some other easiest way to make this working better than SOAP Extension. Is there any way where I can only call the service and a delegate class will be called automatically and I don't need to add any annotation to the reference file? I will share my sample code here.
ServiceManage class:
public class ServiceManager
{
public UserDataService dataService; //web service added at Web Reference
public ServiceManager()
{
dataService = new UserDataService();
getUserServiceRequest rqst = new getUserServiceRequest();
getUserServiceResponse resp = dataService.getUser(rqst);
}
}
Reference.cs
[TraceExtensionAttribute(Name = "First")]
public getUserServiceResponse getUser([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] getUserServiceRequest request) {
object[] results = this.Invoke("getUser", new object[] {
request});
return ((getUserServiceResponse)(results[0]));
}
TraceExtensionAttribute.cs
[AttributeUsage(AttributeTargets.Method)]
public class TraceExtensionAttribute : SoapExtensionAttribute
{
private string mstrName = null;
public override Type ExtensionType
{
get { return typeof(TraceExtension); }
}
public override int Priority
{
get { return 1; }
set { }
}
public string Name
{
get { return mstrName; }
set { mstrName = value; }
}
}
TraceExtension.cs
public class TraceExtension : SoapExtension
{
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attr){//..do something}
public override void Initialize(object initializer){//..do something}
public override Stream ChainStream(Stream stream){//...do something}
public override void ProcessMessage(SoapMessage message) {//..do something}
}
Finally, I found the solution. Just through out Web Reference and add Service Reference instead. Then go to the following link. It works for me.
I am just starting to familiarise myself with ServiceStack and have come upon FluentValidation. I have followed the introductions and created a small Hello App.
My problem is that when I try to validate the request DTO no error messages are returned to describe how it failed validation, only a blank Json object {}.
Myself, I think the validation is autowired to the DTO so there should be no need for me to write any extra code.
The answer is probably blatant but I cannot see it. Any help would be greatly appreciated. My code is below:
namespace SampleHello2
{
[Route("/hello")]
[Route("/hello/{Name}")]
public class Hello
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
public class HelloValidator : AbstractValidator<Hello>
{
public HelloValidator()
{
//Validation rules for all requests
RuleFor(r => r.Name).NotNull().NotEmpty().Equal("Ian").WithErrorCode("ShouldNotBeEmpty");
RuleFor(r => r.Name.Length).GreaterThan(2);
}
}
public class Global : System.Web.HttpApplication
{
public class HelloAppHost : AppHostBase
{
//Tell Service Stack the name of your application and where to find your web services
public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }
public override void Configure(Funq.Container container)
{
//Enable the validation feature
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(HelloValidator).Assembly);
//register any dependencies your services use, e.g:
// container.Register<ICacheClient>(new MemoryCacheClient());
}
}
//Initialize your application singleton
protected void Application_Start(object sender, EventArgs e)
{
new HelloAppHost().Init();
}
}
}
P.S. Really enjoying using ServiceStack, It really is a fantastic project so thanks.
Edit
So for example:
Calling: http://localhost:60063/hello/Ian?format=json returns {"Result":"Hello, Ian"}.
Whereas Calling: http://localhost:60063/hello/I?format=json returns {}.
The second call returns {} where I was expecting auto generated error messages.
I found the answer. It was an overlook on my behalf:
This was in the documentation and I overlooked it:
All Error handling and validation options described below are treated
in the same way - serialized into the ResponseStatus property of your
Response DTO making it possible for your clients applications to
generically treat all Web Service Errors in the same way.
So all that was missing from my code was to add the following line into the HelloResponse class.
public ResponseStatus ResponseStatus { get; set; }
I have the following WCF interface that is exposed via net.tcp:
[ServiceContract]
public interface IMyWCFService
{
[OperationContract]
Response ProcessRequest(Request request);
}
This is driven by the following classes (much simplified for the purposes of this question):
[Serializable]
public abstract class Message
{
[XmlAttribute]
public string Sender { get; set; }
[XmlAttribute]
public string Recevier { get; set; }
}
[Serializable]
public abstract class Response : Message
{
[XmlAttribute]
public int EventCode { get; set; }
}
[Serializable]
public abstract class Request : Message
{
[XmlAttribute]
public string SourceSystem { get; set; }
}
[XmlRoot(Namespace="http://blah.blah.com/blah/")]
public class StringRequest : Request
{
[XmlElement]
public string Payload { get; set; }
}
[XmlRoot(Namespace="http://blah.blah.com/blah/")]
public class StringResponse : Response
{
[XmlElement]
public string Payload { get; set; }
}
Note : We use XMLSerializer rather than DataContractSerializer as these classes have to be compatible with legacy systems that are .NET 2 based.
As the interface uses the abstract Request/Response classes in the ProcessRequest method we have to declare StringResponse / StringRequest as ServiceKnownType, for example:
[ServiceContract]
[ServiceKnownType(typeof(StringRequest))]
[ServiceKnownType(typeof(StringResponse))]
public interface IMyWCFService
{
[OperationContract]
ResponseMessage ProcessRequest(RequestMessage request);
}
This works perfectly and all is good in the world, however.....
The WCF listener is just one component of a much larger framework and the classes described above are used throughout. We have also designed the framework to allow us to add new types of Request/Response messages with relative ease. For example I might add:
public class CustomRequest : Request
{
public MyCustomXmlSerialisableRequestObject Payload { get; set; }
}
public class CustomResponse: Response
{
public MyCustomXmlSerialisableResponseObject Payload { get; set; }
}
Which also works fine until I get the the WCF service interface. When we add a new custom request/response pair we also need to update the ServiceKnownType on the interface to include them. Which then means I have to redeploy the service. So the question is - is there any way I can avoid having to update the interface?
As an example when we used remoting we could pass through any objects we liked as long as they were serialisable so I assume/hope that there is a similar solution in WCF.
EDIT : Update
Following the guidance found here:
http://ashgeek.blogspot.com/2011/02/wcf-serialization-dynamically-add.html
I seem to be on the right track. However when I update the client service reference it pulls in all the dynamically types into the service reference. Which is undesirable as not all clients need to, or should, know about all messages that derive from Request/Response
More importantly I seem to lose the the ServiceClient class that is used to push messages, e.g:
// Client proxy class goes AWOL after service reference update
var client = new MyServiceReference.Client();
var responseMessage = client.ProcessRequest(requestMessage)
At the beginning you are mentioning that you need compatibility with .NET 2.0 services but in the same time you are complaining that something which worked in .NET remoting doesn't work in WCF - you are limited by features possible with .NET 2.0 web services where both server and client must know about transferred types on the service layer = types must be in service description and WSDL. Moreover because you decided to use XmlSerializer you generally lost most of the ways how to achieve that:
ServiceKnowType can load known types from static method
KnownTypes defined in configuration (requires DataContractSerializer)
DataContractResolver (only WCF 4) and loading all derived types on startup (requires DataContractSerializer)
Passing .NET type information in messages (requires NetDataContractSerializer and custom behavior) = generally this is the same functionality as in remoting and it demands sharing types between service and client and both service and client must be .NET application using WCF stuff.
With XmlSerializer you have one option
Return XElement and receive XElement in your service operation and deal with XML by yourselves - doesn't work in .NET 2.0
Edit:
There is no dynamic behavior in service description. It is created only once when the host starts and after that doesn't change until you restart the host. If you need subset of WSDL per client you need separate endpoint for each client and you must define exactly which data contracts should be exposed on each endpoint.