I'm trying to develop a program that handles POST and GET requests.
I've spent countless hours searching around the web for a tutorial that doesn't depend on ASP.NET I do not want to use ASP.NET just standard C#.
How can I achieve this? The furthest I've gotten to is this:
if (HttpMethod.ContentType == "POST") {
// Code here
}
I've made a function HttpListen server on http://localhost:8080/ which sends a response.
What I'm looking for is you do http://localhost:8080/?method=val1&results=val2.
Thanks, Brown.
You're looking for an HTTP server library that is not ASP.NET?
Awkwardly bypassing the question "What's wrong with ASP.NET?"....
Nancy is an awesome lightweight open source library. You can find some samples on github, although the samples are a bit on the heavy side. If you're looking for an extremely basic setup you can get away with a couple dozen lines of code. A good example is the console-based self-hosted sample.
// add such a module class to your assembly, Nancy should find it automagically
public class ResourceModule : NancyModule
{
public ResourceModule() : base("/products")
{
// would capture routes to /products/list sent as a GET request
Get["/list"] = parameters => {
return "The list of products";
};
}
}
// then start the host
using (var host = new NancyHost(new Uri("http://localhost:1234")))
{
host.Start();
// do whatever other work needed here because once the host is disposed of the server is gone
Console.ReadLine();
}
Related
I have a plugin model architecture that creates my Restful WCF services.
(It will be a couple years before we move to Web Api from WCF so, moving to Web Api isn't exactly a solution.)
I have decoupled WCF Microservices that don't reference each other.
EntityAWebService
EntityBWebService
EnityAWebService knows that a service EntityBWebService exists from a configuration, but doesn't reference it.
EntityAWebService and EntityBWebService are plugins. As such, they could be on loaded on the same site.
EntityAWebService makes a call to EntityBWebService using configuration information. The EntityBWebService could be on the same server or a different server.
- If on a different server, the code will continue to use HttpClient.
- If on the same server, go cract the message and send it through the channel without going through HttpClient, operating system's network, and IIS.
Below is the architecture. The orange is what I want to create.
Using HttpClient means EntityAWebService sends a message that is going to hit the operating systems network layer and go through IIS. Neither of which is necessary. It causes performance issues, and as the Entity plugins increase, so does the number of sockets and even using a singleton httpclient, the sockets are leaking.
The orange in the architecture is what doesn't exist yet.
The code knows the Url to call for Entity B Web Service, the message content, and the headers. How would I simulate, in the code represented by the orange box, what IIS does to forward the call through the behaviors and to the Endpoint?
FYI, my current project is too complex to post, so I will create a sample and post it soon.
Sample project: https://github.com/rhyous/DecoupledWcfServices
Turns out I didn't need to use named pipes. However, investigating how to use named pipes taught me what I needed to know. I just needed to use reflection and ChannelFactory. As the ChannelFactory for IIS hosting already exists, named pipes would be redundant.
Example Project here: https://github.com/rhyous/DecoupledWcfServices
And the appropriate snippet (the meat of the solution) is below.
using System;
using System.Collections.Specialized;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
namespace DecoupledWcfServices
{
/// <summary>
/// Service 1 and Service 2 are in the same namespace in this project
/// </summary>
public class MessageBus
{
public string CallOtherWcfService(string url, object content, NameValueCollection headers)
{
var service = GetServiceName(url);
try
{
var netPipeUrl = $"http://localhost:54412/{service}/{service}.svc";
var serviceContractType = typeof(IService2);
var genericChannelFactoryType = typeof(WebChannelFactory<>).MakeGenericType(serviceContractType);
var binding = new WebHttpBinding();
var channelFactory = Activator.CreateInstance(genericChannelFactoryType, binding, new Uri(netPipeUrl)) as WebChannelFactory<IService2>; // I actually won't know it is an IService2 in my project, but getting this far should be enough
var proxy = channelFactory.CreateChannel() as IService2;
using (new OperationContextScope((IContextChannel)proxy))
{
var task = proxy.GetData("some data"); // Might need more work here to know which method to call based on the Url
task.Wait();
return task.Result; // Serialized JSON
}
}
catch (Exception)
{
throw;
}
}
internal string GetServiceName(string url)
{
var index = url.IndexOf(".svc");
var sub = url.Substring(0, index);
index = sub.LastIndexOf("/") + 1;
var sub2 = url.Substring(index, sub.Length - index);
return sub2;
}
}
}
We have a library that is shared in .net between both Web and Windows (forms and console) applications. When used as a Web application, a couple of variables need to be read from cookies. Otherwise it needs to read the same variables from the Windows registry. I cannot seem to work out a good solution to doing this such that the same library compiles for all environments. Specifically, the web libraries for reading cookies would not be included in the Windows apps (and thus break the compile), let alone detecting one environment vs another. Does anyone have a solution to this?
If you host in IIS you can read Environment.GetEnvironmentVariables("APP_POOL_ID") and then act accordingly if the variable exists
Depending on architecture of your library, this information should be provided by the client code. I.e you provide some abstraction layer that will be up to client code to fill in.
I'll show a simple example of what I mean. In your library you have an interface like this:
public interface ISettingsProvider
{
public string GetSettingA();
public string GetSettingB();
}
And then your library code that needs access to settings will have to take a dependency on ISettingsProvider:
public class MyLibraryClient
{
private readonly ISettingsProvider settingsProvider;
public MyLibraryClient(ISettingsProvider settingsProvider)
{
this.settingsProvider = settingsProvider;
}
public void MyAwesomeMethod()
{
var settingA = settingsProvider.GetSettingA();
// do more stuff with your settings
}
}
Then your client code should implement ISettingsProvider:
public class WebSettingsProvider : ISettingsProvider
{
public string GetSettingA()
{
// go get the value from cookies
return Cookies["MyCookie1"];
}
public string GetSettingB()
{
// go get the value from cookies
return Cookies["MyCookie2"];
}
}
And very similar thing goes for settings stored in registry.
And when client code is accessing your library, they will have to instantite an instance of settings provider and give it to you.
This way your library does not know anything about web or Windows. You got to keep your code cleaner and it is all a lot more testable. And you don't have to take dependencies on System.Web and ultimately push that depdency on client code that does not work with web, i.e. Windows applications.
I know you have said you are limited in the amount of changes you can do. My answer to this is: you can't make an omlet without breaking eggs. This will be the most clean way to do what you want, everything else will have drawbacks.
In a Web-Environment you should have HttpContext.Current. If you are calling the same from the Console (or a WinForms-Application) this should be null instead of the Context.
To access this you need a reference to Sytem.Web. There should be no issue when you add this reference and access your backend from the Winforms-Application.
Example:
public bool ImInDaWeb() {
return System.Web.HttpContext.Current!=null;
}
Even in a web-application, HttpContext.Current can be null, but as you are needing this detection for reading/writing cookies you will have to detect this within a valid request already (and not on Application start for example).
So I am very new to SignalR, in fact I've only been using it for a couple of days now. Anyway, I am getting the error below when my application first starts up:
The code for the application in question is located in two projects, a Web API and a Single Page Application (SPA). The first one has my backend code (C#) and the second one my client-side code (AngularJS). I think the problem might be due to the fact that the projects in question run on different ports. The Web API, where my SignalR hub lives, is on port 60161 and the SPA is on 60813. My hub is declared like so:
public class ReportHub : Hub
{
public void SendReportProgress(IList<ReportProgress> reportProgress)
{
this.Clients.All.broadcastReportProgress(reportProgress);
}
public override Task OnConnected()
{
this.Clients.All.newConnection();
return base.OnConnected();
}
}
and then in my Startup.cs file for my Web API I initialize SignalR like this:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.Services.Replace(typeof(IHttpControllerActivator), new NinjectFactory());
config.MessageHandlers.Add(new MessageHandler());
//set up OAuth and Cors
this.ConfigureOAuth(app);
config.EnableCors();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
// Setting up SignalR
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration { EnableJSONP = true });
});
//set up json formatters
FormatterConfig.RegisterFormatters(config.Formatters);
WebApiConfig.Register(config);
app.UseWebApi(config);
}
For my client-side code I use an Angular SignalR API called angular-signalr-hub (Angular-signalr-hub). The client-side follows:
angular
.module("mainApp")
.factory("reportHubService", ["$rootScope", "Hub", reportHubService]);
/// The factory function
function reportHubService($rootScope, Hub) {
var vm = this;
vm.reportName = "None";
// Setting up the SignalR hub
var hub = new Hub("reportHub", {
listeners: {
'newConnection': function(id) {
vm.reportName = "SignalR connected!";
$rootScope.$apply();
},
'broadcastReportProgress': function (reportProgress) {
vm.reportName = reportProgress.reportName;
$rootScope.$apply();
}
},
errorHandler: function(error) {
},
hubDisconnected: function () {
if (hub.connection.lastError) {
hub.connection.start();
}
},
transport: 'webSockets',
logging: true
//rootPath: 'http://localhost:60161/signalr'
});
I did some googling yesterday and one of the suggestions I came upon was to set the SignalR URL to the one of my Web API, which I did (the commented out line above). When I uncomment the line in question, that does seem to do something because if I now go to http://localhost:60161/signalr/hubs in my browser, it does show me the dynamically generated proxy file:
and when I run my application I no longer get the error above, but now it doesn't seem to connect. It gets to the negotiate line and it stops there:
I think it should look like this (this is from a SignalR tutorial I found):
In addition, none of my listeners (declared in my Angular code above) get called, so something is still now working quite right. There should be more lines in the log to the effect that connection was successfully established, etc. What could be the problem here?
UPDATE: upon further debugging i found out the problem is most likely being caused by the ProtocolVersion property being different between the client and the result here:
Because of that it seems it just exists and fails to establish connection.
I figured out what the problem was. My SignalR dependencies were out of date and because of that my client and server versions differed. All I had to do was update (via NuGet Package Manager) all SignalR dependencies to the latest version and now it works.
As a side note, SignalR was not very good at telling me what was wrong. In fact, no error message was displayed, unless of course there was some additional logging somewhere that had to be found or turned on, in addition to the logging I already had (turned on). Either way, it's either not logging certain errors or it makes it difficult to figure out how to turn on all logging. I had to go and debug the JQuery SignalR api to figure out what the problem was, which was a time consuming endeavour.
I'm not sure of the best way to accomplish my goal. Looking for insight. I'm familiar with WebAPI services consumed through WPF and Silverlight but this is my first run at ASP and MVC.
I am building a site to verify contents of a shipment against an electronic manifest (EDI 856). I have a page that displays the shipping data and I need the users to scan each item barcode in the container. I would then like to pass that barcode to a service, verify the item belongs in that shipment and then update the page to show as much.
My plan was to have a single text box into which the user could scan/type the barcode and then submit that data to a WebAPI service which would verify the information and then probably use SignalR to send a message back to the page and update a grid with the item data.
If this is a decent way to go, I'm just not quite sure how to use ajax to call the WebAPI endpoint and provide the data I need.
I would advise against using SignalR in this situtation. What you need, judging from your description, is the most basic use case of submitting an ajax request and receiving a response.
You are not designing a system where you need the server to initiate communication with the browser or anything like that, where sockets (and SignalR as an abstraction over sockets with fallbacks to less suitable protocols) is a huge overkill.
Don't worry, your use case is rather simple.
It's a little out of scope to describe how to setup a WebApi project, how to configure routing, action names, etc. Simple google searches will surely provide ample quality tutorials on getting started.
I'll just try to explain what the general idea is, with some code samples, to get you thinking in the right direction.
You need to create an ApiController.
The simplest version of that Controller will probably look something like this:
public class ShipmentVerificationController : ApiController
{
//this is the response object you will be sending back to the client website
public class VerificationResult
{
public bool Valid;
}
public VerificationResult GetIsItemValid(string BarCode)
{
bool itemIsValid;
// Implement checks against the BarCode string here
itemIsValid = true;
return new VerificationResult { Valid = itemIsValid };
}
}
Note that the inner class represents the response you will be sending back. It should be properly filled out with additional info if needed and probably put into a separate .cs file in the "Models" folder or where ever you see fit.
I have declared it inside the controller for demonstration purposes only
Once you have a WebApi service deployed, it's really easy to send it data from your website and receive the feedback.
To simplify Ajax requests, jQuery is often used.
Once the user inputs the barcode into a textbox, you can hook up an event to check for return key being pressed (most barcode scanners send the return key command after they input the barcode data) and then write something along the lines of:
var barcode = $("#input-field").val();
$.getJSON( "<url_to_your_webapi_service>/api/ShipmentVerification/GetIsItemValid/" + barcode, function( data ) {
if (data.Valid) {
// great, highlight the item as valid
}
else {
//better indicate an error with the scanned item
}
});
Please note that for simplicity I have not included any error handling, url parameter encoding, and most importantly, zero authorization.
Authorization is very important if you deploy the web service to the open web but still do not want anyone to be able to call it.
You will have to research these topics yourself, but I hope I have presented you the core concepts and logic behind a simple service such as this, so you have a base to start with.
If you come up with specific problems and questions post a new question.
I actually found a more simple way to do this. I nixed the idea of using a WebAPI endpoint and just went with a normal controller. I used ajax to prevent the page from refreshing with the new view, since that view is actually just json data with my return values in it.
Hi again stackoverflow,
I am following a tutorial on how to build an Android application in Xamarin and I have encountered an error I cannot resolve on my own.
Hoping anyone of you might shed some light on how to proceed from here:
This code is copied from the tutorial itself (source: pluralsight)
private JsonServiceClient client;
private IList<User> users;
void PopulateSelectUsers ()
{
var response = client.Get(new Users());
users = response.Users.ToList ();
var names = users.Select (u => u.Name);
var usersSpinner = FindViewById<Spinner> (Resource.Id.usersSpinner);
usersSpinner.Adapter = new ArrayAdapter<string> (this, Android.Resource.Layout.SimpleListItem1, names.ToArray ());
}
Where "Users" is a request:
public object Get(Users request)
{
return new UsersResponse { Users = Repository.GetUsers() };
}
[Route("/users", "GET")]
public class Users : IReturn<UsersResponse>
{
}
public class UsersResponse
{
public IEnumerable<User> Users { get; set; }
}
HOWEVER once Xamarin read this line of code:
var response = client.Get(new Users());
then the application in the emulator just crashes and Xamarin leaves me no information on what happened or how to fix it..
It seems that this code works in the tutorial and as I mentioned before, Xamarin leaves me no information on what happened or how to fix it, so my question would be if perhaps one of you know what Is happening or perhaps a way to fix it.
Also perhaps worth mentioning is that I'm using redis to store users.
IF you want to view the userservice it is available here:
http://shan13alwo.cloudapp.net/api/metadata
You can check if code works by sending JSON GET to http://shan13alwo.cloudapp.net/api/users
Thank you in advance,
UPDATE:
I realize I might have been unclear of what I wanted to do but to simplify. What I want to do Is get my users(ienumerable) from my redis database and store them in a List. Using the this code in Xamarin does not work:
var response = client.Get(new Users());
users = response.Users.ToList ();
As Scott previously pointed out to me In another topic made here on Stackoverflow:
ServiceStack v4 was JUST released and using different versions of the servicestack library in Xamarin and Visual Studio resulted in this strange behavior.
Reverting back to V3 of ServiceStack solved my issues.
I would like to thank Scott for your assistance and would like to ask one last thing:
Where can I download the VERSION 3, free license version of the ServiceStack libraries for Android?
(Think its called "AndroidIndie")
Downloading and compiling the solution with the libraries from the lib folder of ServiceStack results in "evaluation software, build valid for 24 hours".
Thank you in advance.