Exception: Protocol error: Unknown transport - asp.net

I installed SignalR using nuget and created a very basic hub.
Then I registered my hubs in global.asax. But I get this exception when I navigate to the url of my hub.
I use ASP.NET MVC 2 and Telerik MVC Extensions.
This is my Global.asax
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("elmah.axd");
routes.IgnoreRoute("favicon.ico");
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
RouteTable.Routes.MapHubs("~/flatwhitehubs");
AreaRegistration.RegisterAllAreas();
//RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Application[ApplicationRepository.Current.StockLockObject] = new object();
Application["InvoiceGeneratorLock"] = new object();
}
and this is my hub:
[HubName("FlatwhiteHub")]
public class FlatwhiteHub : Hub, IConnected, IDisconnect
{
public Task JoinGroup(string groupName)
{
return Groups.Add(Context.ConnectionId, groupName);
}
public Task Connect()
{
throw new NotImplementedException();
}
public Task Reconnect(IEnumerable<string> groups)
{
throw new NotImplementedException();
}
public Task Disconnect()
{
throw new NotImplementedException();
}
}

Related

Swagger UI not showing controllers/routes for ASP.NET API

I'm trying to setup Swagger for my API, I have the interface at http://localhost/myAPI/swagger, but my controllers/routes are not displayed.
I'm using .net-framework, not .net-core
Startup:
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
Route config :
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { id = UrlParameter.Optional }
);
}
}
Controller:
[RoutePrefix("v1/controller")]
public class TestController : ApiController
{
[Route("client")]
[HttpPut]
public HttpResponseMessage CreateClient([FromUri] string id)
{
return new HttpResponseMessage(HttpStatusCode.OK);
}
[Route("portfolio")]
[HttpPost]
public IResponseItem<int> CreatePortfolio([FromUri] string id)
{
return new ResponseItem<int>
{
StatusCode = HttpStatusCode.Created,
Message = "Portfolio successfully created",
Item = 12
};
}
}
Swagger config :
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "WebAPI");
})
.EnableSwaggerUi(c =>
{
});
}
}
I'm new to this so I'm probably missing something
first of all, it seems you made a mistake in RoutePrefix section. If you mean by defining v1/controller to use the name of your controller dynamically in the path, you should put [] around it like this:
[RoutePrefix("v1/[Controller]")]
and about the registration. you need to remove {} from your code.your code should be like the following:
GlobalConfiguration.Configuration
.EnableSwagger(c =>c.SingleApiVersion("v1", "WebAPI"))
.EnableSwaggerUi();
I recommend to register swagger directly into the Application_Start() section.
Your final code should be like this :
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configuration
.EnableSwagger(c => c.SingleApiVersion("v1", "title of your api"))
.EnableSwaggerUi();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
and the address to refer is: http://localhost:yourProgramPort/swagger/docs/v1
I hope it is helpful.

Cannot set a custom contract resolver in web api configuration

How can I set a custom contract resolver in web api configuration? My code is relatively new and has no custom contract resolver till now.
I have added no other customization besides routing.
I tried in three different ways and none worked:
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//attempt 1
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
//attempt 2
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
//attempt 3
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new CustomContractResolver()
};
}
The custom contract resolver code, breakpoint never reaches here when I'm debugging:
public class CustomContractResolver : CamelCasePropertyNamesContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
var regex = new Regex(#"([_])(\w)");
if (regex.IsMatch(propertyName))
{
var result = regex.Replace(propertyName.ToLower(), (match) => { return match.Groups[2].Value.ToUpper(); });
return result;
}
else
return base.ResolvePropertyName(propertyName);
}
}
Is there something that is missing?
Edit 1:
I'm using ASP.NET WebApi 5.2.1 AND MVC 5.2.7, JSON.NET (Newtonsoft.Json) v13.0.1 (and already tried the old v12)
My Global Asax is very simple as well:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register); //<- web api configuration
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); //<- mvc configuration
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
The MVC RouteConfig class:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.ashx/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Edit 2
Here is some test web api controllers:
using System.Web.Http;
namespace Kronos.Web.Geolocalizacao.Controllers.Api
{
public class TestController : ApiController
{
[HttpGet]
public TestModel Obtain()
{
return new TestModel { CODE_IDENTIFICATION = 1, DEFAULT_DESCRIPTION = "TEST DAT THING" };
}
}
public class TestModel
{
public decimal CODE_IDENTIFICATION { get; set; }
public string DEFAULT_DESCRIPTION { get; set; }
}
}
Used the Tabbed Postman chrome addon to test
Postman tests
Your problem has nothing to do with how you are registering your global settings -- setting config.Formatters.JsonFormatter.SerializerSettings.ContractResolver is correct as per this question. Your problem is that Json.NET does not call ResolvePropertyName() when the contract resolver also has a NamingStrategy -- and your base class CamelCasePropertyNamesContractResolver does indeed have a naming strategy.
This can be verified by checking the current Json.NET reference source for DefaultContractResolver.SetPropertySettingsFromAttributes():
if (namingStrategy != null)
{
property.PropertyName = namingStrategy.GetPropertyName(mappedName, hasSpecifiedName);
}
else
{
property.PropertyName = ResolvePropertyName(mappedName);
}
Broken demo fiddle #1 here.
If I simply modify your CustomContractResolver to inherit from DefaultContractResolver (which has a null NamingStrategy by default), then it works:
public class CustomContractResolver : DefaultContractResolver
{
readonly NamingStrategy baseNamingStrategy = new CamelCaseNamingStrategy();
protected override string ResolvePropertyName(string propertyName)
{
var regex = new Regex(#"([_])(\w)");
if (regex.IsMatch(propertyName))
{
var result = regex.Replace(propertyName.ToLower(), (match) => { return match.Groups[2].Value.ToUpper(); });
return result;
}
else
return baseNamingStrategy.GetPropertyName(propertyName, false);
}
}
Fixed demo fiddle #2 here.
However, a cleaner solution would be to replace your custom contract resolver with a custom naming strategy:
public class CustomNamingStrategy : CamelCaseNamingStrategy
{
public CustomNamingStrategy() : base() { }
public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames) : base(processDictionaryKeys, overrideSpecifiedNames) { }
public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) : base(processDictionaryKeys, overrideSpecifiedNames, processExtensionDataNames) { }
readonly Regex regex = new Regex(#"([_])(\w)");
protected override string ResolvePropertyName(string name)
{
if (regex.IsMatch(name))
{
var result = regex.Replace(name.ToLower(), (match) => { return match.Groups[2].Value.ToUpper(); });
return result;
}
return base.ResolvePropertyName(name);
}
}
And then configure it in settings like so:
settings.ContractResolver = new DefaultContractResolver
{
// Set the constructor parameters as per your preference. These values are consistent with CamelCasePropertyNamesContractResolver
NamingStrategy = new CustomNamingStrategy(processDictionaryKeys: true, overrideSpecifiedNames: true),
};
Demo fiddle #3 here.

Unable to reach ASP.NET MVC Web Api endpoint

I am working on an ASP.NET MVC app. I am trying to create a basic API. I created my first Web API controller by right-clicking on Controllers, Add -> Controller... then choosing "Web API 2 Controller - Empty". In the controller code, I have the following:
namespace MyProject.Controllers
{
public class MyApiController : ApiController
{
public IHttpActionResult Get()
{
var results = new[]
{
new { ResultId = 1, ResultName = "Bill" },
new { ResultId = 2, ResultName = "Ted" }
};
return Ok(results);
}
}
}
When I run the app, I enter http://localhost:61549/api/myApi in the browser's address bar. Unfortunately, I get a 404. I'm just trying to create an API endpoint that returns a hard-coded set of JSON objects. I need this to test some client-side JavaScript. What am I doing wrong?
Here are how my routes are registered:
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Make sure that you have the WebApiConfig registration being called, possibly in the Global.asax Application_Start() method. Something like:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
You did not add method name at the end of call. Try this one:
http://localhost:61549/api/myapi/get
Try this approach
namespace MyProject.Controllers
{
public class MyApiController : ApiController
{
public IHttpActionResult Get()
{
var results = new List<ResultModel>
{
new ResultModel() {ResultId = 1, ResultName = "Bill"},
new ResultModel() {ResultId = 2, ResultName = "Ted"}
};
return Ok(results);
}
}
public class ResultModel
{
public int ResultId { get; set; }
public string ResultName { get; set; }
}
}
Api: http://localhost:61549/api/MyApi/get
Hope this helps.

Ninject Interception MVC 3 Controller

I have intereception working with the Ninject Interceptions Extentions and Dynamic Proxy v3.0. I'm trying to class proxy intercept an MVC 3 contoller. The controller is intercepted but the behavior is incorrect. The intereceptor only intercepts calls to public virtual methods on the classes ControllerBase and Controller. My HomeController public virtual methods are never intercepted. Here's my code. I'm thinking of using MVC's Filters to accomplish this instead of Ninject Interception.
public class AuditAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<AuditInterceptor>();
}
}
[Audit] //HomeController method not intercepted.
public virtual ActionResult Index()
{
return View();
}
public class AuditInterceptor : SimpleInterceptor
{
public AuditInterceptor(IAuditor auditor)
{
if (auditor == null)
throw new ArgumentNullException("auditor");
this.auditor = auditor;
}
protected override void OnError(IInvocation invocation, Exception exception)
{
stopWatch.Stop();
AuditEvent auditEvent = new AuditEvent();
auditEvent.ExceptionDescription = exception.Message;
auditEvent.FormName = string.Format("class: {0}, method: {1}", invocation.Request.Method.DeclaringType, invocation.Request.Method.Name);
auditEvent.AppName = appName;
this.auditor.WriteAudit(auditEvent);
auditEvent.LengthOfMethodCall = stopWatch.Elapsed;
base.OnError(invocation, exception);
}
protected override void AfterInvoke(IInvocation invocation)
{
stopWatch.Stop();
AuditEvent auditEvent = new AuditEvent();
auditEvent.ExceptionDescription = defaultExp;
auditEvent.FormName = string.Format("class: {0}, method: {1}", invocation.Request.Method.DeclaringType, invocation.Request.Method.Name);
auditEvent.AppName = appName;
auditEvent.LengthOfMethodCall = stopWatch.Elapsed;
this.auditor.WriteAudit(auditEvent);
}
protected override void BeforeInvoke(IInvocation invocation)
{
stopWatch.Start();
}
}

MVC areas not diplaying when registering routes and areas with MVC extensions

I am using MVC Extension with Autofac and I am having issues with my areas. I'm not sure what I am doing wrong.
Initially I had the following in my global.asax.cs:
public class MvcApplication : AutofacMvcApplication
{
public MvcApplication()
{
Bootstrapper.BootstrapperTasks
.Include<RegisterControllers>();
}
}
protected override void OnStart()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
base.OnStart();
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
With this code my areas displayed well. http://localhost:19857/Administration displays my Index view.
If I want MVC Extensions to register my routes and areas for me then http://localhost:19857/Administration displays nothing, just a 404 error.
This is the updated global.asax.cs to register my routes and areas:
public class MvcApplication : AutofacMvcApplication
{
public MvcApplication()
{
Bootstrapper.BootstrapperTasks
.Include<RegisterAreas>()
.Include<RegisterControllers>()
.Include<RegisterRoutesBootstrapperTask>();
}
protected override void OnStart()
{
RegisterGlobalFilters(GlobalFilters.Filters);
base.OnStart();
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
My RegisterRoutesBootstrapperTask class:
public class RegisterRoutesBootstrapperTask : RegisterRoutesBase
{
public RegisterRoutesBootstrapperTask(RouteCollection routes)
: base(routes)
{
}
protected override void Register()
{
Routes.Clear();
Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
Routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
}
Why won't my areas display?
UPDATE
When I go to http://localhost:19857/Administration then defaults to the Dashboard controllers Index view. Here is my area's registration code:
public override string AreaName
{
get
{
return "Administration";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Administration_default",
"Administration/{controller}/{action}/{id}",
new { controller = "Dashboard", action = "Index", id = UrlParameter.Optional }
);
}
I seem to have sorted out the problem. The problem is with the Routes.Clear(); I took it out and now everything is working fine. Here is my changes that I did to the code above:
public class RegisterRoutesBootstrapperTask : RegisterRoutesBase
{
public RegisterRoutesBootstrapperTask(RouteCollection routes)
: base(routes)
{
}
protected override void Register()
{
Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
Routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Here is my updated global.asax.cs:
public class MvcApplication : AutofacMvcApplication
{
public MvcApplication()
{
Bootstrapper.BootstrapperTasks
.Include<RegisterAreas>()
.Include<RegisterControllers>()
.Include<RegisterRoutesBootstrapperTask>()
.Include<AutoMapperBootstrapperTask>();
}
}

Resources