Giter Site home page Giter Site logo

scottoffen / grapevine-legacy Goto Github PK

View Code? Open in Web Editor NEW
209.0 28.0 52.0 1.85 MB

Embedding A REST Server In Your Application Should Be Simple

Home Page: http://scottoffen.github.io/grapevine-legacy/

License: Apache License 2.0

C# 98.54% Batchfile 0.48% PowerShell 0.97%
grapevine csharp rest-client rest-server

grapevine-legacy's Introduction

Grapevine 4 is in maintenence mode
Please migrate to Grapevine 5

Join the chat at https://gitter.im/sukona/Grapevine

The best solutions are the simplest to implement. Embedding a REST/HTTP server in your application should be simple. Consuming REST resources from inside your application should be simple. If what you've been using doesn't feel simple, try Grapevine. It doesn't get any simpler than this.

Important:
No additional features or enhancements are being made. Bug fixes will be considered on a case-by-case basis.

Introduction

Grapevine is a .NET class library focused on solving two problems:

  1. Easily embedding a REST/HTTP servers in your application
  2. Easily consume REST resources in your application

The focus is on simplicity, and while Grapevine is intended for use in applications for which being a REST or HTTP client or server is not the primary function or purpose of the application, it can just as easily be used to serve up production-ready website and web applications.

Features

  • Grapevine has no dependency on IIS or System.Web.

  • Grapevine can serve both static files and dynamic resources

  • Grapevine can both produce and consume REST services

  • Grapevine has minimal configuration requirements

  • Grapevine allows you to map specific methods to HTTP verbs and URL patterns

  • Grapevine supports using regular expressions

  • Grapevine streamlines connecting and communicating with REST servers using simple patterns and placeholders

  • Grapevine can listen on multiple ports, and scope REST resources to those ports

Limitations

  • Grapevine does not do any script parsing (CGI scripts or HTML templating engines) by default - but feel free to fork this project and hack away! I'm pretty sure it could be done, I just haven't encountered a need for it (yet).

  • You will likely be required to open a port in your firewall for remote computers to be able to send requests to your application. Grapevine will not (yet) automatically do that for you, but it's on our roadmap.

Support

If you find you are having problems and need help check out our support options.

"Grapes In Dark Blue Cloud" Icon courtesy of aha-soft.

grapevine-legacy's People

Contributors

altima avatar beluk avatar darriuswrightgd avatar gitter-badger avatar jordanzaerr avatar kbrimble avatar mattdefoor avatar meiktranel avatar mortifera avatar scottoffen avatar wizicer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grapevine-legacy's Issues

System.ArgumentNullException if host ist not reachable

If the host is not reachable the following lines result in an ArgumentNullException:

        var client = new RESTClient("http://localhost:4444");
        var request = new RESTRequest("test");
        var response = client.Execute(request);

The Message itself says: The value must not be null. Paramater name: cookies

The error is misleading, it should say that the host was not reachable.

InternalServerError override not invoked in implementation of RESTResource

I tried to implement custom route exception handling by overriding the method InternalServerError in my implementation of RESTResource.

My override is never invoked when deliberately throwing an Exception in my route handler method.
I tracked the issue down to the finally block of the ProcessRequest()-method.

As I see it, the methods InternalServerError() and NotFound() should be executed on route.

If I'm right I can provide a pull-request.

Custom Error Response by HttpStatusCode

Rather than simply returning the text of the error code, add a mechanism whereby a custom response body can be attached to a particular HttpStatusCode, such that the developer only has to make a single call and the custom response will be sent instead of the default one.

Ideas

  • Create an attribute for automatic method discovery and registration
  • Allow for manual registration
  • Delegates are registered on route, but not on routing table
  • Arguments should include the HttpContext and an optional HttpStatusCode

Grapevine won't find routes or resources located in assemblies with grapevine in the assembly name

First, thanks for library.
I have lost however some time before I found some really annoying issue.

I wanted to test Grapevine library and created a project which I called... GrapevineTest. Not very original, isn't it?

When I tried to add my own code for REST incoming messages it didn't work. I used your example and it didn't work:

[RESTRoute(Method = HttpMethod.GET)]
public void HandleAllGetRequests(HttpListenerContext context)
{
this.SendTextResponse(context, "GET is a success!");
}

After a long search and being completely stupid why it doesn't work I found this:

private Dictionary<string, RESTResource> LoadRestResources()
{
....              
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            if (assembly.FullName.Matches(@"^(microsoft|mscorlib|vshost|system|grapevine)")) { continue; }

For my project assembly.FullName was GrapevineTest so the library skipped it. When I renamed my project it began to work.

Not a big problem, but I'd like to warn the others :)

Cannot reach the RestServer other than localhost.

Hello ,
I am using VS2012 and Grapevine 3.0.4 , when i use the Grapevine same machine with localhost
hostname , everything works well.
If I want to reach from other PC with client , Server could not be start listening with hostname ip address or Computername

If i try server pc set hostname to localhost , it starts listening but when reached from other PC with IP or name server returns bad request 400

Is it something wrong with my code or library.

My Server code is
public class embeddedHTTP //
{

    private RESTServer Server;

    public void ServerStart()
    {

        try
        {

            Server = new RESTServer();
            Server.Port =  GlobalVars.HttpHostPort;
            Server.Host = GlobalVars.HttpHostAdress; // THIS ONLY WORKS FOR LOCALHOST
            Server.MaxThreads = 20;
            Server.Start();


            while (Server.IsListening)
            {
                Thread.Sleep(GlobalVars.HttpHostRespTime);
            }
        }

        catch (Exception ex)
        {
            messenger.logque("embedded HTTP server not started, Error ID : 52", 3, null);

        }

    }

    public void ServerStop()
    {


        Server.Stop();
    }


    public sealed class MyResource : RESTResource
    {

        //d+$^  [a-zA-Z]+
        [RESTRoute(Method = Grapevine.HttpMethod.GET, PathInfo = @"/")] 
        public void HandleFooRequests(HttpListenerContext context)
        {

       //     String RawuR = context.Request.RawUrl;
            String URL = Convert.ToString(context.Request.Url);
            String ResultXML = brain.HTTPCMD(URL);          
            this.SendTextResponse(context, ResultXML);

        }


     }


    }

Enable and disable individual routes

Add the ability to enable and disable routes. Only enabled routes should show up in the route list for a request, only enabled routes should be executed during routing.

NullReferenceException when initialising RESTRequest

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object
  at Grapevine.Client.RESTRequest.set_Resource (System.String value) [0x00000] in <filename unknown>:0 
  at Grapevine.Client.RESTRequest..ctor (System.String resource, HttpMethod method, ContentType type, Int32 timeout, System.Text.Encoding encoding) [0x00000] in <filename unknown>:0

This happens no matter what is set in the constructor for RESTRequest, both with nothing set and also with the Resource set. It's caused by _parameters being null so it cannot be cleared. I'd PR it but my fork has reformatted everything thanks to MonoDev.

Passing application-specific info to response handlers

What is the appropriate way to communicate application-specific information from the program that starts the server to the request handlers? I'm currently putting that information into static properties of the sealed class that derives from RESTResource, because, unless I've missed it, the program that starts the server has no control over the lifecyle of the instance(s) of that class that are created by the server. Static properties suffice for now, but that approach could complicate things if one needs to start multiple servers. Would you consider allowing user code to instantiate these instances and pass them to the server in the configuration object?

WebException.Response is not always not-null

RestClient.cs Line 63, the WebException instance won't necessarily have a Result that isn't null. When a timeout occurs this is generally null for instance. This results in an NRE when GetResponse() is called in RESTResponse's constructor.

Creating a cluster with multiple RESTServers does not process HTTP requests

[RESTScope(BaseUrl = "http://localhost:1111")]
public sealed class ResourceD : RESTResource
{
    [RESTRoute(Method = HttpMethod.GET, PathInfo = @"^/resource/d")]
    public void MyGetResponder(HttpListenerContext context)
    {
        this.SendTextResponse(context, "Resource D limited to http://localhost:1111");
    }
}

[RESTScope(BaseUrl = "http://localhost:2222")]
public sealed class ResourceE : RESTResource
{
    [RESTRoute(Method = HttpMethod.GET, PathInfo = @"^/resource/e$")]
    public void MyGetResponder(HttpListenerContext context)
    {
        this.SendTextResponse(context, "Resource E limited to http://localhost:2222");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var cluster = new RESTCluster();
        cluster.Add("A", new RESTServer {Port= "1111"});
        cluster.Add("B", new RESTServer {Port= "2222"});

        cluster.StartAll();

        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();
        cluster.StopAll();
    }
}

Language translations for documentation

I've received several requests for examples/documentation in different languages.

  • Chinese
  • Japanese
  • Brazilian Portuguese

I expect there will be more in the future. As I don't know these language, if anyone wants to help me with this, many people would be grateful to you.

Configure EventLogger.LogExceptions from Config object

It'd be nice to configure the value of EventLogger.LogExceptions from the Config object, which would allow you to turn it on and off using an external configuration file. It would make troubleshooting in production easier.

EventLogger.ExceptionToString error when exception.Message == null

title is wrong (can I change that?) there is an exception but Message is not the issue. Not sure why ExceptionToString is throwing, but you wouldn't think it would, would you?

[update] ExceptionToString is throwing because trace.GetFrame(2) is returning null. Because the stack isn't that deep. :)

Proposal 2 still valid: in RESTServer.ProcessRequest, wrap the finally{} block's error handler in a try/finally block to ensure that ctx.Response.Close() and ctx.Close() are always called out of paranoia. (In fact may want to add a second block around the whole function.) Also might want a top level exception handler that tries to use Close(byte[]) to send a generic "something is dreadfully wrong" response.

NullReferenceException if a RestRequest's timeout is reached

There is a NullReference exception when requesting an http server using RestClient that times out or it is unreachable.

The problem is found on RestClient.cs on method Execute.

try
{
    httpresponse = (HttpWebResponse)client.GetResponse();
}
catch (WebException e)
{
    httpresponse = (HttpWebResponse)e.Response;
    error = e.Message;
    errorStatus = e.Status;
}

When there is a timeout, a WebException is raised indicating a timeout. The problem is that the property Response of that object is null. Then, when creating the RestResponse object a couple of lines later, it fails.

var response = new RestResponse(httpresponse, stopwatch.ElapsedMilliseconds, error, errorStatus);

Because you can not call the method GetResponseStream on a null object. This is the first line of the RestResponse constructor:

StreamReader reader = new StreamReader(response.GetResponseStream());

Change *Responder to *Handler

What were you thinking? Responder is technically accurate but confusing! Change it to Handler.

Also, update documentation to reflect this change.

REST Client

Need to implement a REST Client to facilitate initializing REST requests.

PathInfo regex should not match on GET parameters

I'm of the opinion that routes should not take GET parameters into consideration when matching. Currently, the PathInfo is checked against RawUrl which includes GET parameters. This makes it hard to write effective routes, because order of parameters matter.

My routes are all starting to take this kind of shape, especially since they will be used in JSONP calls:

[RESTRoute(Method = HttpMethod.GET, PathInfo = @"^/poll/(\?[^/]*)?$")]

If users need to use GET parameters, then they should be extracted from within the route handler and validated there. NotFound can be returned on missing parameters.

Unfortunately, there aren't any properties that I can find on context.Request that expose just the path portion of the URL. If this is accepted, I'd probably split on ? and take the first match.

Note that I'm actually using GrapevinePlus (great work by the way), but I figured that issues relating to both should be raised here.

Thanks.

Static file expire time is usually in the past

expireDate = "last write time" + 23 hours. What you probably want is DateTime.Now + 23 hours. Expires is dependent on the system clock being correct and probably a bad choice, unless also combined with max-age and used maily for backward compatibility.

I would probably change it to "max-age": age + 86400 (1d), leaving the Last-Modified exactly as it is and removing Expires or changing it to be relative to DateTime.Now.

        var lastWriteTime = File.GetLastWriteTimeUtc(path);
        var lastModified = lastWriteTime.ToString("R");
        var maxAge = (long)((DateTime.UtcNow - lastWriteTime).TotalSeconds + 86400);

Proposal: Middleware concept

I'd like to introduce a middleware concept to Grapevine. The goals are:

  • keep route handlers DRY by doing common steps of several routes (e.g. authentication) in one place
  • open up a possibility for the community to implement stuff that others need as well
  • as a consequence of the above: easily do stuff by plugging in middleware written by others

Everyone who has used expressJS knows what I'm talking about. You can read about the concept here: http://expressjs.com/guide/using-middleware.html

The gist is, that there is not one route handler but there can be multiple route handlers for a request and if a route handler decides to answer a request he can do so. But he can also decide to pass the handling to the next route handler of the ones that match the route regex. This enables to have e.g. authentication checks of several different routes to be handled in one place.

To make it happen there are a few things that need to be done:

  • define the middleware method call API
  • maybe open up the possibility to register middleware/route handlers via a (fluent) api on the server instance.
  • use Priority on the method attributes to define which middleware comes first, otherwise the first registered one comes first(scottoffen/grapevine#15)
  • some internal logic how grapevine builds and handles the "middleware-stack" for a specific request has to be implemented, but I think it is not too complicated.

Please comment if you think that this should be part of grapevine or if you think that it is not needed. Cheers :)

The I/O operation has been aborted because of either a thread exit or an application request

Hi, It's a great library to have slim web server on any machine.

When I try to dispose all the resources that I use including RESTServer I get the below exception

"The I/O operation has been aborted because of either a thread exit or an application request"

Just create a simple console with the below lines, please turn on the CLR exception

RESTServer server = Init(8008, "sampleapi");
server.Start();
Console.ReadLine();
server.Dispose();

I tried few options before submitting this request the exception still occurs.

Many thanks

PathInfo return matches as parameters?

I find myself re-matching path parts in my handlers. I am considering modifying the RESTServer to pass any matches from its regex match (PathInfo) as an optional extra parameter to the handler. Does this seem desirable?

The more complicated part of this is backward compatibilty, so it would need to detect the method signature, as I am pretty sure Invoke() will barf if the array size does not match the invoked method signature.

The obvious solution is something like like void MyGetHandler( HttpListenerContext ctx, string [] matches ) or similar. Other options include:

  1. a variable number of string parameters, but that prevents any future additions
  2. dictionary of values, using named regex match patterns (does RegEx support this?)
  3. not bothering at all

Just a thought. it just irks me to write my patterns twice. It also irks me to see 50-odd regex patterns recompiled on every http request, but that's for another issue I guess. :)

Here is an example: most of my handlers look like this:

  static readonly Regex GetSomethingStatusParams = 
     new Regex( @"^/api/something/(?<id>[^/]*)/status" );

  [RESTRoute(Method = HttpMethod.GET, 
             PathInfo = @"^/api/something/([^/]*)/status$")]
  public void HttpGetSomethingStatus( HttpListenerContext ctx )
  {
     // UrlMatcher throws rest specific exceptions on failure for convenience...
     UrlMatcher matcher = new UrlMatcher( GetSomethingStatusParams, ctx.Request.RawUrl );
     SendJsonResponse( ctx, GetSomethingStatus( matcher.GetLong( "id" ) ) );
  }

Which is a bit cumbersome. The Server could, say, check whether (MethodInfo.Parameters.Length > 1), and if so, pass the match from the regex into the function, leading to something along the lines of:

  [RESTRoute(Method = HttpMethod.GET, PathInfo = @"^/api/something/(<id>[^/]*)/status$")]
  public void HttpGetSomethingStatus( HttpListenerContext ctx, Match urlMatch )
  {
     long id = _ConvertToLong( urlMatch.Groups["id"].Value );
     SendJsonResponse( ctx, GetSomethingStatus( id );

Should be doable, prevents multiply-typing patterns, etc. Desirable?

...Another quick update: I have implemented this--it's pretty simple really. I want to clean up the implementation and add tests (how do I run these on mono!?). Also I made it against GrapevinePlus (oops) and need to.. backport? upport? sideport it? It would be pretty simple to do magic "name matching" like WebApi and other apis do, but personally I think just returning the matching Match is more flexible, simple, and fits with the whole "simple" approach of Grapevine.

Starting the RESTServer should throw an exception if anything goes wrong

Yesterday I had a problem which took a while to figure out:

var server = new RESTServer();
server.Start();

We didn't fire it up with admin privileges so the HttpListener throw an exception. We had no clue it did until we debugged inside the Grapevine start method.

I think an exception which prevented the server start should in no case be swallowed because the user of the library is the one who has to handle this not the library itself.

Of course there is a logger so if this is turned on at least something is visible. But how should an application relying on the server listening should handle the event where the server is NOT running because an exception was thrown?

At the very least there should be the possibility to pass an action that is executed with the exception is parameter to indicate the failure of the failed attempt to start the server. Otherwise there is no proper way for the application to handle the failure.

I also am aware of the possibility to check the IsListening-property but this is not giving access to the exception which I might want to have.

Authentication

REST Client currently does not support authentication schemas by default. Authentication needs to be implemented by the consumer of the package.

ThreadAbortException when doing UnitTests involving starting a RESTServer

While implementing some tests in an application where a RESTServer is started this exception occurred at the end of the test:

An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll and wasn't    
handled before a managed/native boundaryAdditional information Der Thread wurde abgebrochen.

This stack trace of external code was visible:

mscorlib.dll!System.Threading.WaitHandle.WaitAny(System.Threading.WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)  Unknown
mscorlib.dll!System.Threading.WaitHandle.WaitAny(System.Threading.WaitHandle[] waitHandles) Unknown
Grapevine.dll!Grapevine.Server.RESTServer.Worker()  Unknown
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state)    Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()    Unknown

The tests are green so it is only noticeable when the debugger is attached. It is just an exception occurring when the test runner is tearing down the test environment.

I am reporting this because this even happens when I stop the the RESTServer in the test code. I don't understand why the exception still occurs at the end. Maybe the ThreadAbortException can be catched?

Implement thread-safe RestServer.Stop() for use in routes

Ok, this might rather be a issue in the documentation than in the code, but anyway ...

Using the suggested ...

[RESTRoute(Method = HttpMethod.DELETE, PathInfo = @"^/shutdown$")]
public void HandleShutDownRequests(HttpListenerContext context)
{
    this.SendTextResponse(context, "shutting down");
    this.Server.Stop();
}

to remotely shutdown the Server does not work for me. If I use it as suggested, I get a deadlock in the RestServer.Stop() method, which does not surprise me because of the

foreach (Thread worker in this._workers)
{
    worker.Join();
}

that can be found there. The RESTRoute that invoked the stop uses one of these workers, doesn't it?

So, I'm using this instead:

[RESTRoute(Method = HttpMethod.GET, PathInfo = @"^/exit$")]
public void HandleShutDownRequests(HttpListenerContext context)
{
    this.SendTextResponse(context, "shutting down");
    // create a new thread that will kill the server asynchronously
    (new Thread(() => Server.Stop() )).Start();
}

PS: Thanks for making this available!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.