How to get a list of all the headers for logging in web api - asp.net-web-api

I want to log all the request headers. I already have a filter like so.
Now how do I get all the request header so that I can log them?
public class LogApiFilter : AbstractActionFilter
{
private readonly ILog m_Log;
public override bool AllowMultiple
{
get
{
return true;
}
}
public LogApiFilter(ILog iLog)
{
if (iLog == null)
throw new ArgumentNullException("log instance injected is null.");
m_Log = iLog;
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
}
public override void OnActionExecuting(HttpActionContext context)
{
m_Log.Debug("Web api Controller Name and Action method Name: "
+ context.ActionDescriptor.ControllerDescriptor.ControllerName
+ ", " + context.ActionDescriptor.ActionName);
base.OnActionExecuting(context);
}
}

Ok, for my own records and for others, I have comeup with this. Please do suggest if there is a better way.
private string GetRequestHeaders(HttpActionContext context)
{
// Note you can replace the type names sucha as string, HttpRequestHeaders, List<KeyValuePair<string, IEnumerable<string>>>
// with var keyword where ever possible for readability.
string headerString = string.Empty;
HttpRequestHeaders requestHeaders = context.Request.Headers;
List<KeyValuePair<string, IEnumerable<string>>> headerList = requestHeaders.ToList();
foreach (var header in headerList)
{
string key = header.Key;
List<string> valueList = header.Value.ToList();
string valueString = string.Empty;
foreach (var v in valueList)
{
valueString = valueString + v + "-";
}
headerString = headerString + key + ": " + valueString + Environment.NewLine;
}
return headerString;
}
The above method can be called from the action filter in the question. I am calling it from the method, OnActionExecuting(HttpActionContext context).
I am using ninject for di, so this is how I have configured it.
kernel.BindHttpFilter<LogApiFilter>(System.Web.Http.Filters.FilterScope.Global);
kernel.BindHttpFilter<ApiExceptionFilterAttribute>(System.Web.Http.Filters.FilterScope.Global);
kernel.BindFilter<LogMvcFilter>(System.Web.Mvc.FilterScope.Global, 0);

Related

Invoke lambda function handler java

I have a lambda function which has a handler which inturn has multiple routers. Each router corresponds to an API.
I have created a lambda client in java and need to call those APIs. To call these APIs, I need to invoke the handler and pass a payload to the client along with it. Can you guys help me with the syntax for invoking the handler and passing the payload.
If I understand your question correctly I first created a Lambda that looked like:
public class SampleHandler implements RequestStreamHandler {
private static final Logger logger = LogManager.getLogger(SampleHandler.class);
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
logger.info("handlingRequest");
LambdaLogger lambdaLogger = context.getLogger();
ObjectMapper objectMapper = new ObjectMapper();
String inputString = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining("\n"));
JsonNode jsonNode = objectMapper.readTree(inputString);
String route = jsonNode.get("route").asText();
RouterResult routerResult = new RouterResult();
switch( route ) {
case "requestTypeA":
RequestTypeA requestTypeA = objectMapper.readValue(inputString, RequestTypeA.class);
routerResult.setResult(handleRequestTypeA(requestTypeA));
break;
case "requestTypeB":
RequestTypeB requestTypeB = objectMapper.readValue(inputString, RequestTypeB.class);
routerResult.setResult(handleRequestTypeB(requestTypeB));
break;
default:
logger.error( "don't know how to handle route of type \"" + route + "\n" );
routerResult.setResult("error");
}
outputStream.write(objectMapper.writeValueAsString(routerResult).getBytes(StandardCharsets.UTF_8));
logger.info("done with run, remaining time in ms is " + context.getRemainingTimeInMillis() );
}
private String handleRequestTypeA(RequestTypeA requestTypeA) {
logger.info("handling requestTypeA, requestTypeA.requestA is " + requestTypeA.getRequestA() );
return "handled requestTypeA";
}
private String handleRequestTypeB(RequestTypeB requestTypeB) {
logger.info("handling requestTypeB, requestTypeB.requestB is " + requestTypeB.getRequestB() );
return "handled requestTypeB";
}
}
with RouterRequest.java:
public class RouterRequest {
protected String route;
public String getRoute() {
return route;
}
}
and RequestTypeA.java:
public class RequestTypeA extends RouterRequest {
private String requestA;
public RequestTypeA() {
route = "requestTypeA";
}
public String getRequestA() {
return requestA;
}
public void setRequestA(String requestA) {
this.requestA = requestA;
}
}
and RequestTypeB.java
public class RequestTypeB extends RouterRequest {
private String requestB;
public RequestTypeB() {
route = "requestTypeB";
}
public String getRequestB() {
return requestB;
}
public void setRequestB(String requestB) {
this.requestB = requestB;
}
}
And a result class, RouterResult.java:
public class RouterResult {
private String result;
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
#Override
public String toString() {
return "RouterResult{" +
"result='" + result + '\'' +
'}';
}
}
Then, to invoke this Lambda, you will need a role that has the lambda:InvokeFunction permission. The code to invoke looks like:
public class RouterRunner {
private static final String AWS_ACCESS_KEY_ID = "<access key>";
private static final String AWS_SECRET_ACCESS_KEY = "<access secret>";
public static void main( String[] argv ) throws IOException {
AWSCredentials credentials = new BasicAWSCredentials( AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY );
AWSLambda lambda = AWSLambdaClientBuilder.standard()
.withRegion(Regions.US_WEST_2)
.withCredentials(new AWSStaticCredentialsProvider(credentials)).build();
RequestTypeA requestTypeA = new RequestTypeA();
requestTypeA.setRequestA("set from the runner, request type A");
ObjectMapper objectMapper = new ObjectMapper();
InvokeRequest invokeRequest = new InvokeRequest()
.withFunctionName("lambda-router")
.withPayload(objectMapper.writeValueAsString(requestTypeA));
invokeRequest.setInvocationType(InvocationType.RequestResponse);
InvokeResult invokeResult = lambda.invoke(invokeRequest);
String resultJSON = new String(invokeResult.getPayload().array(), StandardCharsets.UTF_8);
System.out.println( "result from lambda is " + resultJSON );
RouterResult routerResult = objectMapper.readValue(resultJSON, RouterResult.class);
System.out.println( "result.toString is " + routerResult.toString() );
RequestTypeB requestTypeB = new RequestTypeB();
requestTypeB.setRequestB("set from the runner, request type B");
invokeRequest = new InvokeRequest()
.withFunctionName("lambda-router")
.withPayload(objectMapper.writeValueAsString(requestTypeB));
invokeRequest.setInvocationType(InvocationType.RequestResponse);
invokeResult = lambda.invoke(invokeRequest);
resultJSON = new String(invokeResult.getPayload().array(), StandardCharsets.UTF_8);
System.out.println( "result from lambda is " + resultJSON );
routerResult = objectMapper.readValue(resultJSON, RouterResult.class);
System.out.println( "result.toString is " + routerResult.toString() );
}
}
There likely needs to be some error handling improvement and I'm sure you could make this a bit more efficient. But that's the overall idea. Ultimately on the Lambda side I convert the InputStream to a String and convert that String to some sort of object based on a common field in the request types. On the client side I convert the objects into JSON, send them out, and convert the result back from a JSON String back into the result object.

Filehelpers Field max length

I'm working with Filehelpers and imported a csv File. Everything works fine, but now I want to validate the length of the imported Fields.
[DelimitedRecord(";")]
public class ImportFile
{
public string Name;
public string NameSurname;
}
Is there a possible way, that I can create an attribute "MaxLength" which split the Input String or Throw an Exception, if the InputString is bigger than my MaxLength Attribut?
The only thing I found was the FieldFlixedLength, but thats only the Split, the Inputfile in fields.
You can implement an AfterRead event as follows:
[DelimitedRecord(";")]
public class ImportRecord : INotifyRead<ImportRecord>
{
public string Name;
public string NameSurname;
public void BeforeRead(BeforeReadEventArgs<ImportRecord> e)
{
}
public void AfterRead(AfterReadEventArgs<ImportRecord> e)
{
if (e.Record.Name.Length > 20)
throw new Exception("Line " + e.LineNumber + ": First name is too long");
if (e.Record.NameSurname.Length > 20)
throw new Exception("Line " + e.LineNumber + ": Surname name is too long");
}
}
class Program
{
static void Main(string[] args)
{
var engine = new FileHelperEngine<ImportRecord>();
engine.ErrorMode = ErrorMode.SaveAndContinue;
string fileAsString = "Firstname;SurnameIsAVeryLongName" + Environment.NewLine
+ "FirstName;SurnameIsShort";
ImportRecord[] validRecords = engine.ReadString(fileAsString);
Console.ForegroundColor = ConsoleColor.Red;
foreach (ErrorInfo error in engine.ErrorManager.Errors)
{
Console.WriteLine(error.ExceptionInfo.Message);
}
Console.ForegroundColor = ConsoleColor.White;
foreach (ImportRecord validRecord in validRecords)
{
Console.WriteLine(String.Format("Successfully read record: {0} {1}", validRecord.Name, validRecord.NameSurname));
}
Console.WriteLine("Press any key...");
Console.ReadKey();
}
}

How to capture MVXTrace in error reporting tool

I'm using MvvmCross and playing around with some ways to get the MvxTrace in my reporting tool. In this case I'm using Raygun. Raygun gives me the option of including additional messages to the error message that I want to throw, which is what I'm thinking I have to use to get this to happen. Basically I want to do something like this in the code:
var client = new RaygunClient();
var tags = new List<string> { "myTag" };
var customData = new Dictionary<int, string>() { {1, "**MVXTrace stuff here**"} };
client.Send(exception, tags, customData);
How can I hook this up? I'm getting confused when I'm looking at the Trace setup. I'm assuming I need to do something with my DebugTrace file that I'm using to inject. Right now it looks like this:
public class DebugTrace : IMvxTrace
{
public void Trace(MvxTraceLevel level, string tag, Func<string> message)
{
Debug.WriteLine(tag + ":" + level + ":" + message());
}
public void Trace(MvxTraceLevel level, string tag, string message)
{
Debug.WriteLine(tag + ":" + level + ":" + message);
}
public void Trace(MvxTraceLevel level, string tag, string message, params object[] args)
{
try
{
Debug.WriteLine(string.Format(tag + ":" + level + ":" + message, args));
}
catch (FormatException)
{
Trace(MvxTraceLevel.Error, tag, "Exception during trace of {0} {1} {2}", level, message);
}
}
}
Can I do something that hooks into the IMvxTrace logic to attach inner exceptions and etc to my RaygunClient? It's hard for me to see what is causing specific errors because if I leave it the way it is I get errors that look like this:
[MvxException: Failed to construct and initialize ViewModel for type MyProject.Core.ViewModels.SignatureViewModel from locator MvxDefaultViewModelLocator - check MvxTrace for more information]
Cirrious.MvvmCross.ViewModels.MvxViewModelLoader.LoadViewModel(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request, IMvxBundle savedState, IMvxViewModelLocator viewModelLocator):0
Cirrious.MvvmCross.ViewModels.MvxViewModelLoader.LoadViewModel(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request, IMvxBundle savedState):0
Cirrious.MvvmCross.Droid.Views.MvxAndroidViewsContainer.ViewModelFromRequest(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest viewModelRequest, IMvxBundle savedState):0
Cirrious.MvvmCross.Droid.Views.MvxAndroidViewsContainer.CreateViewModelFromIntent(Android.Content.Intent intent, IMvxBundle savedState):0
Cirrious.MvvmCross.Droid.Views.MvxAndroidViewsContainer.Load(Android.Content.Intent intent, IMvxBundle savedState, System.Type viewModelTypeHint):0
Cirrious.MvvmCross.Droid.Views.MvxActivityViewExtensions.LoadViewModel(IMvxAndroidView androidView, IMvxBundle savedState):0
Cirrious.MvvmCross.Droid.Views.MvxActivityViewExtensions+<>c__DisplayClass3.<OnViewCreate>b__1():0
Cirrious.MvvmCross.Views.MvxViewExtensionMethods.OnViewCreate(IMvxView view, System.Func`1 viewModelLoader):0
Cirrious.MvvmCross.Droid.Views.MvxActivityViewExtensions.OnViewCreate(IMvxAndroidView androidView, Android.OS.Bundle bundle):0
Cirrious.MvvmCross.Droid.Views.MvxActivityAdapter.EventSourceOnCreateCalled(System.Object sender, Cirrious.CrossCore.Core.MvxValueEventArgs`1 eventArgs):0
(wrapper delegate-invoke) System.EventHandler`1<Cirrious.CrossCore.Core.MvxValueEventArgs`1<Android.OS.Bundle>>:invoke_void__this___object_TEventArgs (object,Cirrious.CrossCore.Core.MvxValueEventArgs`1<Android.OS.Bundle>)
Cirrious.CrossCore.Core.MvxDelegateExtensionMethods.Raise[Bundle](System.EventHandler`1 eventHandler, System.Object sender, Android.OS.Bundle value):0
Cirrious.CrossCore.Droid.Views.MvxEventSourceActivity.OnCreate(Android.OS.Bundle bundle):0
MyProject.Droid.Views.SignatureView.OnCreate(Android.OS.Bundle bundle):0
Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState):0
(wrapper dynamic-method) object:3af7783d-a44d-471c-84a6-662ebfaea4ae (intptr,intptr,intptr)
It would be really helpful, as that message suggests, if I could get the MvxTrace with it to track down exactly why initializing this ViewModel failed. Any suggestions?
This is how I do it on Android. I use the Android.Util.Log class. This will then log the messages to the Android Device Log.
public class DebugTrace : IMvxTrace
{
public void Trace(MvxTraceLevel level, string tag, Func<string> message)
{
Trace(level, tag, message());
}
public void Trace(MvxTraceLevel level, string tag, string message)
{
switch (level)
{
case MvxTraceLevel.Diagnostic:
Log.Debug(tag, message);
break;
case MvxTraceLevel.Warning:
Log.Warn(tag, message);
break;
case MvxTraceLevel.Error:
Log.Error(tag, message);
break;
default:
Log.Info(tag, message);
break;
}
}
public void Trace(MvxTraceLevel level, string tag, string message, params object[] args)
{
try
{
Trace(level, tag, string.Format(message, args));
}
catch (FormatException)
{
Trace(MvxTraceLevel.Error, tag, "Exception during trace of {0} {1}", level, message);
}
}
}
You can then get the log using the following:
public class AndroidLogReader
{
public string ReadLog(string tag)
{
var cmd = "logcat -d";
if (!string.IsNullOrEmpty(tag)) cmd += " -s " + tag;
var process = Java.Lang.Runtime.GetRuntime().Exec(cmd);
using (var sr = new StreamReader(process.InputStream))
{
return sr.ReadToEnd();
}
}
}
Here is what I did to get this to work for me:
I have a BaseView that I'm using for all of my Android activities. I make use of this BaseView to hook up and log Unhandled Exceptions like so:
public abstract class BaseView : MvxActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
AndroidEnvironment.UnhandledExceptionRaiser += HandleAndroidException;
}
protected void HandleUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
var e = (Exception)args.ExceptionObject;
Mvx.Trace(MvxTraceLevel.Error, "Exception: {0}", e.ToLongString());
var logReader = new AndroidLogReader();
var logMessages = logReader.ReadLog("mvx:E");
var customData = new Dictionary<string, string> { { "logMessage", logMessages } };
var session = SessionController.Instance;
var user = new RaygunIdentifierMessage(session.UserName + " " + session.Company);
var rayMessage = RaygunMessageBuilder.New
.SetEnvironmentDetails()
.SetMachineName(Environment.MachineName)
.SetClientDetails()
.SetExceptionDetails(e)
.SetUser(user)
.SetUserCustomData(customData)
.Build();
RaygunClient.Current.Send(rayMessage);
}
protected void HandleAndroidException(object sender, RaiseThrowableEventArgs e)
{
var exception = e.Exception;
Mvx.Trace(MvxTraceLevel.Error, "Exception: {0}", e.Exception.ToLongString());
var logReader = new AndroidLogReader();
var logMessages = logReader.ReadLog("mvx:E");
var customData = new Dictionary<string, string> { { "logMessage", logMessages } };
var session = SessionController.Instance;
var user = new RaygunIdentifierMessage(session.UserName + " " + session.Company);
var rayMessage = RaygunMessageBuilder.New
.SetEnvironmentDetails()
.SetMachineName(Environment.MachineName)
.SetClientDetails()
.SetExceptionDetails(exception)
.SetUser(user)
.SetUserCustomData(customData)
.Build();
RaygunClient.Current.Send(rayMessage);
}
}
My DebugTrace.cs looks like so:
public class DebugTrace : IMvxTrace
{
public void Trace(MvxTraceLevel level, string tag, Func<string> message)
{
Trace(level, tag, message());
}
public void Trace(MvxTraceLevel level, string tag, string message)
{
switch (level)
{
case MvxTraceLevel.Diagnostic:
Log.Debug(tag, message);
break;
case MvxTraceLevel.Warning:
Log.Warn(tag, message);
break;
case MvxTraceLevel.Error:
Log.Error(tag, message);
break;
default:
Log.Info(tag, message);
break;
}
}
public void Trace(MvxTraceLevel level, string tag, string message, params object[] args)
{
try
{
Trace(level, tag, string.Format(message, args));
}
catch (FormatException)
{
Trace(MvxTraceLevel.Error, tag, "Exception during trace of {0} {1} {2}", level, message);
}
}
}
And my AndroidLogReader looks like so:
public class AndroidLogReader
{
public string ReadLog(string tag)
{
var cmd = "logcat -d";
if (!string.IsNullOrEmpty(tag))
{
cmd += " -s " + tag;
}
var process = Java.Lang.Runtime.GetRuntime().Exec(cmd);
using (var sr = new StreamReader(process.InputStream))
{
return sr.ReadToEnd();
}
}
}
With these things in place I now get custom data attached to all of my Raygun errors that includes the stack trace for all errors from Mvx. Thank you so much #Kiliman for pointing me towards the building blocks to get this to work!

How to make queryparams mandatory in Java Jersey REST services?

I have a REST API that accepts 3 query params. When the query is called without any one of the query parameters, the API executes and returns the result. How do we make the queryparams mandatory? How can I add validation to check if all the parameters are present? Also, please let me know the best approach.
On a very simple level you could just inject the HttpServletRequest and check yourself:
#GET
public Response example(#Context HttpServletRequest request,
#QueryParam("name") String name) {
if (null == request.getParameter("name")) {
ResponseBuilder builder = Response.status(404);
return builder.build();
}
// Do something with name
}
Or you can implement something more elaborate using AOP. Here's a blog post about further options.
jersey doesn't give a mandatory parameter checking functionality out of the box. however you can do something like implementing your own annotation to achieve it.
Below is the annotation code:
#Target(value = ElementType.METHOD)
#Retention(value = RetentionPolicy.RUNTIME)
public #interface Required {
String[] value();
}
You also need a filter, below is the code:
public class RequiredParamResourceFilterFactory implements ResourceFilterFactory {
#Context
private transient HttpServletRequest servletRequest;
private class RequiredParamFilter implements ResourceFilter, ContainerRequestFilter {
private final String[] requiredParams;
protected List<String> parametersValueMissing;
private RequiredParamFilter(String[] requiredParams) {
this.requiredParams = requiredParams;
}
#Override
public ContainerRequest filter(ContainerRequest containerRequest) {
boolean missingMandatoryParameter = false;
List<String> missingParameters = new ArrayList<String>();
List<String> requiredParametersValueMissing = new ArrayList<String>();
List<String> URLParameters = getURLParameters(containerRequest.getQueryParameters());
List<String> methodRequiredParameters = Arrays.asList(requiredParams);
if (methodRequiredParameters != null) {
for (String methodRequiredParam : methodRequiredParameters) {
if (URLParameters == null) {
missingMandatoryParameter = true; //we will check this flag before returning result set to caller
missingParameters.add(methodRequiredParam);
} else if (!URLParameters.contains(methodRequiredParam)) {
missingMandatoryParameter = true; //we will check this flag before returning result set to caller
missingParameters.add(methodRequiredParam);
//Add to required parameters value missing List, only if the parameter is mandatory and value is not provided
// in the URL
} else if (parametersValueMissing.contains(methodRequiredParam)) {
requiredParametersValueMissing.add(methodRequiredParam);
}
}
if (missingMandatoryParameter && requiredParametersValueMissing.size() > 0) {
throw new YourCustomException("Missing Parameters = " + StringHelper.ArrayToString(missingParameters) +
"\nParameter value missing for " + StringHelper.ArrayToString(requiredParametersValueMissing));
} else if (missingMandatoryParameter) {
throw new YourCustomException("Missing Parameters = " + StringHelper.ArrayToString(missingParameters), MisbarErrorCode.VALIDATION_WRONG_INPUT_ERROR, "Customers");
} else if (requiredParametersValueMissing != null &&
requiredParametersValueMissing.size() > 0) {
throw new YourCustomException("Parameter value missing for " + StringHelper.ArrayToString(requiredParametersValueMissing));
}
}
return containerRequest;
}
#Override
public ContainerRequestFilter getRequestFilter() {
return this;
}
#Override
public ContainerResponseFilter getResponseFilter() {
return null;
}
/**
* To fetch the parameters sent to webservice call, these will be used to find if required parameter
* are present or not
*
* #param queryParams the queryparams sent
* #return all the parameters sent in URL
*/
private List<String> getURLParameters(MultivaluedMap<String,String> queryParams) {
parametersValueMissing = new ArrayList<String>();
List<String> arr = new ArrayList<String>();
for(String key:queryParams.keySet())
{
arr.add(key);
if(queryParams.get(key)==null)
parametersValueMissing.add(key);
}
if(!arr.isEmpty())
return arr;
return null;
}
}
#Override
public List<ResourceFilter> create(AbstractMethod am) {
Required required = am.getAnnotation(Required.class);
if(required!=null)
{
return Collections.<ResourceFilter>singletonList(new RequiredParamFilter(required.value()));
}
return null;
}
}
Below sample shows how to use this annotation, so in below webservice; file_id and count are mandatory parameters:
#GET
#Produces(MediaType.APPLICATION_JSON+";charset=utf-8")
#Cacheable(isCacheable = true)
#Path("posts/clusters")
#Required({"file_id","count"})
#Timed
public Response getClusters(
#QueryParam("file_id") Integer fileId,
#QueryParam("count") Integer count,
#DefaultValue("-1")#QueryParam("start_time") Long startTime){
;
}
If mandatory parameters are not provided in webservice call, you receive an error like below, mentioning the parameter names that are missing:
{
message: "Missing Parameters = file_id, count",
errorCode: "600"
}
Hope this solves your problem.

Trying to call code in my controller but getting Null Reference error

Don't want to over-complicate the issue, but I think I need to post all the code that's hooked into this error.
Using MvcMailer and introduced a separate Send mechanism (for use with Orchard CMS' own EMail).
The MvcMailer Code:
1) AskUsMailer.cs:
public class AskUsMailer : MailerBase, IAskUsMailer
{
public AskUsMailer()
: base()
{
//MasterName = "_Layout";
}
public virtual MvcMailMessage EMailAskUs(AskUsViewModel model)
{
var mailMessage = new MvcMailMessage { Subject = "Ask Us" };
ViewData.Model = model;
this.PopulateBody(mailMessage, viewName: "EMailAskUs");
return mailMessage;
}
}
2) IAskUsMailer.cs:
public interface IAskUsMailer : IDependency
{
MvcMailMessage EMailAskUs(AskUsViewModel model);
}
3) AskUsController.cs: (GETTING NULL REFERENCE ERROR BELOW)
[Themed]
public ActionResult Submitted()
{
//This is the new call (see new code below):
//Note: Debugging steps through eMailMessagingService,
//then shows the null reference error when continuing to
//SendAskUs
eMailMessagingService.SendAskUs(askUsData);
//Below is normal MvcMailer call:
//AskUsMailer.EMailAskUs(askUsData).Send();
return View(askUsData);
}
Note: askUsData is defined in a separate block in the controller:
private AskUsViewModel askUsData;
protected override void OnActionExecuting(ActionExecutingContext
filterContext)
{
var serialized = Request.Form["askUsData"];
if (serialized != null) //Form was posted containing serialized data
{
askUsData = (AskUsViewModel)new MvcSerializer().
Deserialize(serialized, SerializationMode.Signed);
TryUpdateModel(askUsData);
}
else
askUsData = (AskUsViewModel)TempData["askUsData"] ??
new AskUsViewModel();
TempData.Keep();
}
protected override void OnResultExecuted(ResultExecutedContext
filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["askUsData"] = askUsData;
}
I did not know how to get my EMailMessagingService.cs (see below) call into the controller, so in a separate block in the controller I did this:
private IEMailMessagingService eMailMessagingService;
public AskUsController(IEMailMessagingService eMailMessagingService)
{
this.eMailMessagingService = eMailMessagingService;
}
I think this is part of my problem.
Now, the new code trying to hook into Orchard's EMail:
1) EMailMessagingServices.cs:
public class EMailMessagingService : IMessageManager
{
private IAskUsMailer askUsMailer;
private IOrchardServices orchardServices;
public EMailMessagingService(IAskUsMailer askUsMailer,
IOrchardServices orchardServices)
{
this.orchardServices = orchardServices;
this.askUsMailer = askUsMailer;
this.Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void SendAskUs(AskUsViewModel model)
{
var messageAskUs = this.askUsMailer.EMailAskUs(model);
messageAskUs.To.Add("email#email.com");
//Don't need the following (setting up e-mails to send a copy anyway)
//messageAskUs.Bcc.Add(AdminEmail);
//messageAskUs.Subject = "blabla";
Send(messageAskUs);
}
....
}
The EMailMessagingService.cs also contains the Send method:
private void Send(MailMessage messageAskUs)
{
var smtpSettings = orchardServices.WorkContext.
CurrentSite.As<SmtpSettingsPart>();
// can't process emails if the Smtp settings have not yet been set
if (smtpSettings == null || !smtpSettings.IsValid())
{
Logger.Error("The SMTP Settings have not been set up.");
return;
}
using (var smtpClient = new SmtpClient(smtpSettings.Host,
smtpSettings.Port))
{
smtpClient.UseDefaultCredentials =
!smtpSettings.RequireCredentials;
if (!smtpClient.UseDefaultCredentials &&
!String.IsNullOrWhiteSpace(smtpSettings.UserName))
{
smtpClient.Credentials = new NetworkCredential
(smtpSettings.UserName, smtpSettings.Password);
}
if (messageAskUs.To.Count == 0)
{
Logger.Error("Recipient is missing an email address");
return;
}
smtpClient.EnableSsl = smtpSettings.EnableSsl;
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
messageAskUs.From = new MailAddress(smtpSettings.Address);
messageAskUs.IsBodyHtml = messageAskUs.Body != null &&
messageAskUs.Body.Contains("<") &&
messageAskUs.Body.Contains(">");
try
{
smtpClient.Send(messageAskUs);
Logger.Debug("Message sent to {0} with subject: {1}",
messageAskUs.To[0].Address, messageAskUs.Subject);
}
catch (Exception e)
{
Logger.Error(e, "An unexpected error while sending
a message to {0} with subject: {1}",
messageAskUs.To[0].Address, messageAskUs.Subject);
}
}
}
Now, in EMailMessagingService.cs I was getting an error that things weren't being implemented, so I auto-generated the following (don't know if this is part of my error):
public void Send(Orchard.ContentManagement.Records.ContentItemRecord recipient, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public void Send(System.Collections.Generic.IEnumerable<Orchard.ContentManagement.Records.ContentItemRecord> recipients, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public void Send(System.Collections.Generic.IEnumerable<string> recipientAddresses, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public bool HasChannels()
{
throw new NotImplementedException();
}
public System.Collections.Generic.IEnumerable<string> GetAvailableChannelServices()
{
throw new NotImplementedException();
}
2) IEMailMessagingServices.cs
public interface IEMailMessagingService
{
MailMessage SendAskUs(AskUsViewModel model);
}
MvcMailer works fine without this addition (outside of Orchard), but I am trying to get everything working within Orchard.
I just cannot figure out what I am doing wrong. Any thoughts?
Sorry for excessive code.
IEmailMessaginService does not implement IDependency, so it can't be found by Orchard as a dependency. That's why it's null.

Resources